• 03:数据结构 栈、队列、链表与数组


    算法其他篇

    目录:

    1.1 数据结构中的一些概念     返回顶部

      1、数据结构是什么

          1、简单来说,数据结果就是设计数据以何种方式存储在计算机中
          2、比如:列表,集合,与字典等都是一种数据结构
          3、程序 = 数据结构 + 算法

      2、数据结构与数据类型

        1)数据类型:

          说明:数据类型是一个值的集合和定义在此集合上一组操作(通常是增删改查或者操作读写的方法)的总称

          数据类型:int、str、boolean、byte

        2)数据结构:

          说明:数据以什么方式构成,如何进行存储(数据结构是数据类型中的一种:结构类型

          数据结构:数组、栈、队列、链表、树、图、堆、散列表等

          python数据结构:列表、集合、字典、元祖

      3、数据结构与数据类型比较

          1. 数据类型的分类为:原子类型 和 结构类型;

          2. 原子类型  = 一种值的集合 + 定义在值集合上的一组操作。(比如:python中的int,float,字符串)

          3. 结构类型  = 一种数据结构 + 定义在这种数据结构上的一组操作。(比如:python中的列表,字典,元组)

          原子类型 + 结构类型 = 数据类型

           注:数据类型是一个值的集合和定义在此集合上一组操作(通常是增删改查或者操作读写的方法)的总称

           

    1.2 栈(stack)     返回顶部

      1、栈的定义

                      栈是一种数据集合,可以理解为只能在一端进行插入或删除操作的列表

      2、栈的特点

                      后进先出(last-in, first-out)

      3、栈的概念

                      栈顶,栈底

      4、栈的基本操作

                      进栈(压栈):push

                      出栈:pop

                      取栈顶:gettop

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    class Stack(object):
    
        def __init__(self):
            self.stack = []              # 初始化一个栈
    
        def push(self,item):             # 入栈
            self.stack.append(item)
    
        def gettop(self):                # 获取栈顶元素
            return self.stack[-1]
    
        def pop(self):                   # 出栈
            return self.stack.pop()
    
    
    if __name__ == '__main__':
        s = Stack()
        s.push(1)
        s.push(2)
        print(s.stack)
    python实现栈功能

      5、栈的使用匹配括号是否成对出现

    def check_kuohao(s):
       stack = []
       for char in s:
          if char in ['(','[','{']:
             stack.append(char)
          elif char == ')':
             if len(stack)>0 and stack[-1] == '(':
                stack.pop()
             else:
                return False
          elif char == ']':
             if len(stack) > 0 and stack[-1] == '[':
                stack.pop()
             else:
                return False
          elif char == '}':
             if len(stack) > 0 and stack[-1] == '{':
                stack.pop()
             else:
                return False
       if len(stack) == 0:
          return True
       else:
          return False
    print(check_kuohao('(){}{}[]'))  #True
    匹配括号是否成对出现

    1.3 队列     返回顶部

      1、队列定义

          1、队列是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除
          2、插入的一端称为队尾(rear),插入动作叫进队或入队
          3、进行删除的一端称为对头(front),删除动作称为出队
          4、队列性质:先进先出(First-in, First-out)
          5、双向队列:队列的两端都允许进行进队和出队操作

      2、对列使用方法

          1、导入: from collectios import deque
          2、创建队列:queue = deque(li)
          3、进队: append
          4、出队: popleft
          5、双向队列队首进队:appendleft
          6、双向队列队尾出队:pop

    from queue import Queue
    #1. 基本FIFO队列  先进先出 FIFO即First in First Out,先进先出
    #2. maxsize设置队列中,数据上限,小于或等于0则不限制,容器中大于这个数则阻塞,直到队列中的数据被消掉
    q = Queue(maxsize=0)
    
    #3. 写入队列数据
    q.put(0)
    q.put(1)
    q.put(2)
    
    #4. 输出当前队列所有数据
    print(q.queue)
    
    #5. 删除队列数据,并返回该数据
    q.get()
    
    #6. 输也所有队列数据
    print(q.queue)
    python操作队列queue

      3、双向对列原理图

          1、 环形对列:当对位指针front == Maxsize + 1 时,再进一个位置就自动到0
          2、 实现方法:求余数运算
          3、 队首指针前进1: front = (front + 1)%MaxSize
          4、 队尾指针前进1:rear = (rear+1)%MaxSize
          5、 队空条件:rear == front
          6、 队满条件:(rear+1)%MaxSize == front

                    

      4、队列应用场景

          1. 队列主要的功能是在多个进程间共享数据,实现业务解耦,提高效率

          2. 生产者线程只需要把任务放入队列中,消费者线程只需要到队列中取数据进行处理

      5、队列与列表区别

          1. 列表中数据虽然是排列的,但数据被取走后还会保留,而队列中这个容器的数据被取后将不会保留

    1.4 链表     返回顶部

      1、单链表

        注:链表中每个元素都是一个对象,每个对象称为一个节点,包含有数据域key和指向下一节点的指针next,通过各个节点间的相互连接,最终串联成一个链表

        

    class Node(object):
        def __init__(self, item,next=None):
            self.item = item
            self.next = next
    l = Node(1,Node(2,Node(3,Node(4))))
    print(l.item)
    print(l.next.item)
    python模拟链表数据类型
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    class Node(object):
        def __init__(self, item):
            self.item = item
            self.next = None
    
    
    class DLinkList(object):
        def __init__(self):
            self._head = None
    
        def is_empty(self):
            return self._head == None
    
        def append(self, item):
            '''尾部追加元素'''
            node = Node(item)
            if self.is_empty():
                self._head = node
            else:
                cur = self._head
                while cur.next != None:
                    cur = cur.next
                cur.next = node
    
        def add(self, item):
            """头部插入元素"""
            node = Node(item)
            if self.is_empty():
                self._head = node         # 如果是空链表,将_head指向node
            else:
                node.next = self._head      # 将node的next指向_head的头节点
                self._head = node        # 将_head 指向node
    
        def travel(self):
            cur = self._head
            while cur != None:
                print cur.item,
                cur = cur.next
            print ""
    
        def remove(self, item):
            """删除元素"""
            if self.is_empty():
                return
            else:
                cur = self._head
                if cur.item == item:
                    # 如果首节点的元素即是要删除的元素
                    if cur.next == None:  # 如果链表只有这一个节点
                        self._head = None
                    else:  # 将_head指向第二个节点
                        self._head = cur.next
                    return
                while cur != None:
                    if cur.next.item == item:
                        cur.next = cur.next.next
                        break
                    cur = cur.next
    
        def insert(self, pos, item):
            """在指定位置添加节点"""
            if pos <= 0:
                self.add(item)
            elif pos > (self.length() - 1):
                self.append(item)
            else:
                node = Node(item)
                cur = self._head
                count = 0
                # 移动到指定位置的前一个位置
                while count < (pos - 1):
                    count += 1
                    cur_next = cur.next
                # 将node的next指向cur的下一个节点
                cur.next = node
                node.next = cur_next
    
        def length(self):
            """返回链表的长度"""
            cur = self._head
            count = 0
            while cur != None:
                count += 1
                cur = cur.next
            return count
    
    
    if __name__ == '__main__':
        ll = DLinkList()
        # 1、将链表后面追加三个元素:1,2,3
        ll.append(1)
        ll.append(2)
        ll.append(3)
        ll.travel()  # 1 2 3
    
        # 2、将链表头部插入一个元素:0
        ll.add(0)
        ll.travel()  # 1 2 3  ==>  0 1 2 3
    
        # 3、删除链表中的元素:3
        ll.remove(3)
        ll.travel()  # 0 1 2 3  ==>  0 1 2
    
        # 4、在链表的第2号位置插入元素:8
        ll.insert(2,8)
        ll.travel()  # 0 1 2  ==>  0 8 1 2 
    单链表增删改查
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    class Node(object):
        def __init__(self, val):
            self.val = val
            self.next = None
    
    def list_reverse(head):
        if head == None:
            return None
        L, R, cur = None, None, head  # 左指针、有指针、游标
        while cur.next != None:
            L = R             # 左侧指针指向以前右侧指针位置
            R = cur           # 右侧指针前进一位指向当前游标位置
            cur = cur.next    # 游标每次向前进一位
            R.next = L        # 右侧指针指向左侧实现反转
        cur.next = R          # 当跳出 while 循环时 cur(原链表最后一个元素) R(原链表倒数第二个元素)
        return cur
    
    if __name__ == '__main__':
        '''
        原始链表:1 -> 2 -> 3 -> 4
        反转链表:4 -> 3 -> 2 -> 1
        '''
        l1 = Node(1)
        l1.next = Node(2)
        l1.next.next = Node(3)
        l1.next.next.next = Node(4)
        l = list_reverse(l1)
        print l.val         # 4  反转后链表第一个值4
        print l.next.val    # 3  第二个值3
    链表反转
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    class ListNode(object):
        def __init__(self, val, next=None):
            self.val = val
            self.next = next
    
    # 归并法: 对链表排序
    class Solution:
    
        def sortList(self, head):
            if head is None or head.next is None:
                return head
            pre = head
            slow = head  # 使用快慢指针来确定中点
            fast = head
            while fast and fast.next:
                pre = slow
                slow = slow.next
                fast = fast.next.next
    
            left = head
            right = pre.next
            pre.next = None  # 从中间打断链表
            left = self.sortList(left)
            right = self.sortList(right)
            return self.merge(left, right)
    
        def merge(self, left, right):
            pre = ListNode(-1)
            first = pre
            while left and right:
                if left.val < right.val:
                    pre.next = left
                    pre = left
                    left = left.next
                else:
                    pre.next = right
                    pre = right
                    right = right.next
            if left:
                pre.next = left
            else:
                pre.next = right
            return first.next
    
    
    node1 = ListNode(4)
    node2 = ListNode(3)
    node3 = ListNode(2)
    node4 = ListNode(1)
    
    node1.next = node2
    node2.next = node3
    node3.next = node4
    
    s = Solution()
    result = s.sortList(node1)
    
    while (result != None):
        print result.val,    # 1 2 3 4
        result = result.next
    链表排序:归并排序算法实现
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    def mergesort(seq):
        if len(seq) <= 1:
            return seq
        mid = int(len(seq) / 2)
        left = mergesort(seq[:mid])
        right = mergesort(seq[mid:])
        return merge(left, right)
    
    def merge(left, right):
        result = []
        i, j = 0, 0
        while i < len(left) and j < len(right):
            if left[i] <= right[j]:
                result.append(left[i])
                i += 1
            else:
                result.append(right[j])
                j += 1
        result += left[i:]
        result += right[j:]
        return result
    
    if __name__ == '__main__':
        seq = [10,4,6,3,8,2,5,7]
        print mergesort(seq)  # [2, 3, 4, 5, 6, 7, 8, 10]
    对python列表排序:归并排序 对比

      2、双链表

        注:双链表中每个节点有两个指针:一个指针指向后面节点、一个指向前面节点

        

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    class Node(object):
        """双向链表节点"""
        def __init__(self, item):
            self.item = item
            self.next = None
            self.prev = None
    
    
    class DLinkList(object):
        """双向链表"""
        def __init__(self):
            self._head = None
    
        def is_empty(self):
            """判断链表是否为空"""
            return self._head == None
    
        def length(self):
            """返回链表的长度"""
            cur = self._head
            count = 0
            while cur != None:
                count += 1
                cur = cur.next
            return count
    
        def travel(self):
            """遍历链表"""
            cur = self._head
            while cur != None:
                print cur.item,
                cur = cur.next
            print ""
    
        def add(self, item):
            """头部插入元素"""
            node = Node(item)
            if self.is_empty():
                # 如果是空链表,将_head指向node
                self._head = node
            else:
                # 将node的next指向_head的头节点
                node.next = self._head
                # 将_head的头节点的prev指向node
                self._head.prev = node
                # 将_head 指向node
                self._head = node
    
        def append(self, item):
            """尾部插入元素"""
            node = Node(item)
            if self.is_empty():
                # 如果是空链表,将_head指向node
                self._head = node
            else:
                # 移动到链表尾部
                cur = self._head
                while cur.next != None:
                    cur = cur.next
                # 将尾节点cur的next指向node
                cur.next = node
                # 将node的prev指向cur
                node.prev = cur
    
        def search(self, item):
            """查找元素是否存在"""
            cur = self._head
            while cur != None:
                if cur.item == item:
                    return True
                cur = cur.next
            return False
    
        def insert(self, pos, item):
            """在指定位置添加节点"""
            if pos <= 0:
                self.add(item)
            elif pos > (self.length() - 1):
                self.append(item)
            else:
                node = Node(item)
                cur = self._head
                count = 0
                # 移动到指定位置的前一个位置
                while count < (pos - 1):
                    count += 1
                    cur = cur.next
                # 将node的prev指向cur
                node.prev = cur
                # 将node的next指向cur的下一个节点
                node.next = cur.next
                # 将cur的下一个节点的prev指向node
                cur.next.prev = node
                # 将cur的next指向node
                cur.next = node
    
        def remove(self, item):
            """删除元素"""
            if self.is_empty():
                return
            else:
                cur = self._head
                if cur.item == item:
                    # 如果首节点的元素即是要删除的元素
                    if cur.next == None:
                        # 如果链表只有这一个节点
                        self._head = None
                    else:
                        # 将第二个节点的prev设置为None
                        cur.next.prev = None
                        # 将_head指向第二个节点
                        self._head = cur.next
                    return
                while cur != None:
                    if cur.item == item:
                        # 将cur的前一个节点的next指向cur的后一个节点
                        cur.prev.next = cur.next
                        # 将cur的后一个节点的prev指向cur的前一个节点
                        cur.next.prev = cur.prev
                        break
                    cur = cur.next
    
    
    if __name__ == "__main__":
        ll = DLinkList()
        ll.add(1)
        ll.add(2)
        # ll.append(3)
        # ll.insert(2, 4)
        # ll.insert(4, 5)
        # ll.insert(0, 6)
        # print "length:",ll.length()
        # ll.travel()
        # print ll.search(3)
        # print ll.search(4)
        # ll.remove(1)
        print "length:",ll.length()
        ll.travel()
    双链表增删改查
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    class Node(object):
        def __init__(self, item):
            self.item = item
            self.next = None
            self.prev = None
    
    
    class DLinkList(object):
        def __init__(self):
            self._head = None
    
        def is_empty(self):
            return self._head == None
    
        def append(self, item):
            node = Node(item)
            if self.is_empty():
                self._head = node
            else:
                cur = self._head
                while cur.next != None:
                    cur = cur.next
                cur.next = node
                node.prev = cur
    
        def travel(self):
            cur = self._head
            while cur != None:
                print cur.item,
                cur = cur.next
    
    
    if __name__ == '__main__':
        ll = DLinkList()
        ll.append(1)
        ll.append(2)
        ll.append(3)
        # print ll._head.item              # 打印第一个元素:1
        # print ll._head.next.item         # 打印第二个元素:2
        # print ll._head.next.next.item    # 打印第三个元素:3
        ll.travel()    # 1 2 3
    双链表追加和遍历

    1.5 python中字典对象实现原理     返回顶部

        注:字典类型是Python中最常用的数据类型之一,它是一个键值对的集合,字典通过键来索引,关联到相对的值,理论上它的查询复杂度是 O(1) 

      1、哈希表 (hash tables)

          1. 哈希表(也叫散列表),根据关键值对(Key-value)而直接进行访问的数据结构。

          2. 它通过把key和value映射到表中一个位置来访问记录,这种查询速度非常快,更新也快。

          3. 而这个映射函数叫做哈希函数,存放值的数组叫做哈希表。 

          4. 通过把每个对象的关键字k作为自变量,通过一个哈希函数h(k),将k映射到下标h(k)处,并将此对象存储在这个位置。

      2、具体操作过程

          1. 数据添加:把key通过哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,
                            将value存储在以该数字为下标的数组空间里。

          2. 数据查询:再次使用哈希函数将key转换为对应的数组下标,并定位到数组的位置获取value。

      3、{“name”:”zhangsan”,”age”:26} 字典如何存储的呢? 

          1. 比如字典{“name”:”zhangsan”,”age”:26},那么他们的字典key为name、age,假如哈希函数h(“name”) = 1、h(“age”)=3,

          2. 那么对应字典的key就会存储在列表对应下标的位置,[None, “zhangsan”, None, 26 ]

      4、解决hash冲突

          

      5、python字典操作时间复杂度

          

    1.6 数组     返回顶部

      1、数组定义

          1. 所谓数组,就是相同数据类型的元素按一定顺序排列的集合

          2. 在Java等其他语言中并不是所有的数据都能存储到数组中,只有相同类型的数据才可以一起存储到数组中。

          3. 因为数组在存储数据时是按顺序存储的,存储数据的内存也是连续的,所以他的特点就是寻址读取数据比较容易,插入和删除比较困难

          

      2、python中list与数组比较

          1. python中的list是python的内置数据类型,list中的数据类不必相同的,而array的中的类型必须全部相同。

          2. 在list中的数据类型保存的是数据的存放的地址,简单的说就是指针,并非数据

          3. 否则这样保存一个list就太麻烦了,例如list1=[1,2,3,'a']需要4个指针和四个数据,增加了存储和消耗cpu。

          

     

     

  • 相关阅读:
    尴尬的事情又发生Newtonsoft.Json vs Protobuf.net
    python的多线程到底有没有用?
    Python中单线程、多线程和多进程的效率对比实验
    Python 一篇学会多线程
    Python中threading的join和setDaemon的区别及用法
    Python 函数定义以及参数传递
    python的thread和threading区别
    mod_python
    Maven 入门
    微信开发 没有认证过的服务号怎么办?微信提供了測试号(开通了认证过的服务号的功能)
  • 原文地址:https://www.cnblogs.com/xiaonq/p/8574655.html
Copyright © 2020-2023  润新知