zoukankan      html  css  js  c++  java
  • 基础数据结构

    基础数据结构

    栈(stack)

      栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。
    这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,
    它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,
    它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
    
    栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,
    先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
    栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。
    
    - 特性:先进后出的数据结构
    
    # 应用:每个 web 浏览器都有一个返回按钮。当你浏览网页时,这些网页被放置在一个栈中(实际是网页的网址)。
    你现在查看的网页在顶部,你第一个查看的网页在底部。如果按‘返回’按钮,将按相反的顺序浏览刚才的页面。
    
    # 使用python代码实现一个栈
    - Stack() 创建一个空的新栈。 它不需要参数,并返回一个空栈。
    - push(item)将一个新项添加到栈的顶部。它需要 item 做参数并不返回任何内容。
    - pop() 从栈中删除顶部项。它不需要参数并返回 item 。栈被修改。
    - peek() 从栈返回顶部项,但不会删除它。不需要参数。 不修改栈。
    - isEmpty() 测试栈是否为空。不需要参数,并返回布尔值。
    - size() 返回栈中的 item 数量。不需要参数,并返回一个整数。
    
    class Stack():
        def __init__(self):
            self.items = []
        def push(self,item):
            self.items.append(item)
        def pop(self):
            return self.items.pop()
        def peek(self):
            return len(self.items) - 1
        def isEmpty(self):
            return self.items == []
        def size(self):
            return len(self.items)
        
    stack = Stack()
    stack.push(1)
    stack.push(2)
    stack.push(3)
    
    print('栈顶元素下标:',stack.peek())
    print(stack.isEmpty())
    print('元素个数:',stack.size())
    print(stack.pop())
    print(stack.pop())
    print(stack.pop())
    

    队列 (queue)

    - 队列:先进先出
    - 应用场景:
        - 我们的计算机实验室有 30 台计算机与一台打印机联网。当学生想要打印时,
    他们的打印任务与正在等待的所有其他打印任务“一致”。第一个进入的任务是先完成。
    如果你是最后一个,你必须等待你前面的所有其他任务打印。
    
    # 使用python代码实现一个队列
    - Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
    - enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
    - dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。
    - isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
    - size() 返回队列中的项数。它不需要参数,并返回一个整数。
    
    class Queue():
        def __init__(self):
            self.items = []
        def enqueue(self,item):
            self.items.insert(0,item)
        def dequeue(self):
            return self.items.pop()
        def isEmpty(self):
            return self.items == []
        def size(self):
            return len(self.items)
    
    q = Queue()
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    print(q.dequeue())
    print(q.dequeue())
    print(q.dequeue())    
    
    # 面试题
    - 烫手的山芋
        - 烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,
    需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。
    该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。
    # 解题思路
        - 让手里有山芋的孩子永远排在队列的头部
    class Queue():
        def __init__(self):
            self.items = []
        def enqueue(self,item):
            self.items.insert(0,item)
        def dequeue(self):
            return self.items.pop()
        def isEmpty(self):
            return self.items == []
        def size(self):
            return len(self.items)
        
    kids = ['A','B','C','D','E','F']
    queue = Queue()
    for kid in kids:
        queue.enqueue(kid) #A对头F队尾
    while queue.size() > 1:
        for i in range(6): #每循环一次,山芋传递一次,手里有山芋的孩子永远在对头位置
            kid = queue.dequeue()
            queue.enqueue(kid)
        queue.dequeue()
    print('获胜的选手是:',queue.dequeue())
    for a in range(len(kids)):
        if kids[a] == kid:   
            print('排在第:%d会获胜'%a)  
    # 执行结果
    获胜的选手是: E
    排在第:4会获胜
    

    # 面试题 使用两个队列实现一个栈
    class Queue():
        def __init__(self):
            self.items = []
        def enqueue(self,item):
            self.items.insert(0,item)
        def dequeue(self):
            return self.items.pop()
        def size(self):
            return len(self.items)
        
    alist = [1,2,3,4,5]
    q1 = Queue()
    for i in alist:
        q1.enqueue(i)
    q2 = Queue()
    while q1.size() > 0:
        #将q1中的n-1个值取出放入到q2中
        while q1.size() > 1:
            item = q1.dequeue()
            q2.enqueue(item)
        print(q1.dequeue())
    
        q1,q2 = q2,q1    
    

    双端队列 ( deque )

    同队列相比,有两个头部和尾部。可以在双端进行数据的插入和删除,提供了单数据结构中栈和队列的特性.
    
    # 用python代码实现一个双端队列
    - Deque() 创建一个空的新 deque。它不需要参数,并返回空的 deque。
    - addFront(item) 将一个新项添加到 deque 的首部。它需要 item 参数 并不返回任何内容。
    - addRear(item) 将一个新项添加到 deque 的尾部。它需要 item 参数并不返回任何内容。
    - removeFront() 从 deque 中删除首项。它不需要参数并返回 item。deque 被修改。
    - removeRear() 从 deque 中删除尾项。它不需要参数并返回 item。deque 被修改。
    - isEmpty() 测试 deque 是否为空。它不需要参数,并返回布尔值。
    - size() 返回 deque 中的项数。它不需要参数,并返回一个整数。
    
    class Deque():
        def __init__(self):
            self.items = []
        def addFront(self,item):
            self.items.insert(0,item)
        def addRear(self,item):
            self.items.append(item)
        def removeFront(self):
            return self.items.pop()
        def removeRear(self):
            return self.items.pop(0)
        def isEmpty(self):
            return self.items == []
        def size(self):
            return len(self.items)
        
    q = Deque()
    q.addFront(1)
    q.addFront(2)
    q.addFront(3)
    
    print(q.removeRear())
    print(q.removeRear())
    print(q.removeRear())
    
    - 双端队列应用案例:回文检查
        - 回文是一个字符串,读取首尾相同的字符,例如,radar toot madam。
    class Deque():
        def __init__(self):
            self.items = []
        def addFront(self,item):
            self.items.insert(0,item)
        def addRear(self,item):
            self.items.append(item)
        def removeFront(self):
            return self.items.pop()
        def removeRear(self):
            return self.items.pop(0)
        def isEmpty(self):
            return self.items == []
        def size(self):
            return len(self.items)
        
    def isHuiWen(s):
        ex = True
        q = Deque()
        for ch in s:
            q.addFront(ch)
        while q.size() > 1:
            if q.removeFront() != q.removeRear():
                ex = False
                break
        return ex
    print(isHuiWen('上海自来水来自海上'))
    # 执行结果
    True
    

    顺序表 与 内存

    • 简单了解一下内存

    - 内存在计算机的作用
        - 用来存储和运算二进制的数据
    - 问题:计算机如何计算1+2?
        - 将1和2的二进制类型的数据加载到计算机的内存中,然后使用寄存器进行数值的预算。
    - 变量的概念
        - 变量可以理解为某一块内存(实际是引用的某一块内存的地址)
        - 内存空间是有两个默认的属性:
            - 内存空间的大小
                - bit(位):一个bit大小的内存空间只能存放一位二进制的数
                - byte(字节):8bit
                - kb:1024byte
            - 内存空间的地址
                - 使用一个十六进制的数值表示
                - 作用:让cup寻址
                           
    - 理解a=10的内存图(引用,指向)
        - 引用:变量==》内存空间的地址
        - a = 10:a变量/引用/内存空间的地址
        - 指向:如果变量或者引用表示的是某一块内存空间地址的话,则该变量或者该引用指向了该块内存
    
    • 顺序表

    - 集合中存储的元素是有顺序的,顺序表的结构可以分为两种形式:单数据类型(np.array数组)和多数据类型(列表,元组)。
    
    - python中的列表和元组就属于多数据类型的顺序表
    
    - 单数据类型顺序表的内存图 (内存连续开辟,每个内存空间大小一致)
    

    - 多数据类型顺序表的内存图(内存非连续开辟)
    

    • 顺序表的弊端:顺序表的结构需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁。

    链表 (Linked list)

    - 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,
    而是每一个结点(数据存储单元)里存放下一个结点的信息(即地址)
    
    - 相对于顺序表,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理且进行扩充时不需要进行数据搬迁。
    

    - 使用python实现单向链表
    
    . is_empty():链表是否为空
    
    . length():链表长度
    
    . travel():遍历整个链表
    
    . add(item):链表头部添加元素
    
    . append(item):链表尾部添加元素
    
    . insert(pos, item):指定位置添加元素
    
    . remove(item):删除节点
    
    . search(item):查找节点是否存在
    
    # 代码
    class Node():
        def __init__(self,item):
            self.item = item
            self.next = None
            
    class Link():
        def __init__(self):
            #构造出一个空链表
            #_head存储的只能是空或者第一个节点的地址
            self._head = None
        #向链表的头部插入一个节点
        def add(self,item):
            #创建一个新的节点
            node = Node(item)
            node.next = self._head
            self._head = node
            
        def travel(self):
            #_head在链表创建好之后一定是不可变
            cur = self._head
            while cur:
                print(cur.item)
                cur = cur.next
                
        def isEmpty(self):
            return self._head == None
        
        def size(self):
            cur = self._head
            count = 0
            while cur:
                count += 1
                cur = cur.next
            return count
        
        def append(self,item):
            node = Node(item)
            #特殊情况
            if self._head == None:
                self._head = node
                return
            
            cur = self._head
            pre = None#pre指向的是cur前一个节点
            while cur:
                pre = cur
                cur = cur.next
            pre.next = node
        
        def search(self,item):
            find = False
            
            cur = self._head
            while cur:
                if cur.item == item:
                    find = True
                    break
                cur = cur.next
            
            return find
        
        def insert(self,pos,item):
            node = Node(item)
            pre = None
            cur = self._head
            for i in range(pos):
                pre = cur
                cur = cur.next
            pre.next = node
            node.next = cur
            
        def remove(self,item):
            cur = self._head
            pre = None
            #删除的是第一个节点
            if cur.item == item:
                self._head = cur.next
                return
            while cur:  
                pre = cur
                cur = cur.next
                if cur.next == None:
                    return
                if cur.item == item:
                    pre.next = cur.next
                    return      
    
    - 如何实现将单链表倒置
    
    # 单链表(插入,删除,遍历)
    class Node():
       def __init__(self,item):
           self.item = item
           self.next = None
    class Link():
       def __init__(self):
           self._head = None
       def append(self,item):
           node = Node(item)
           if self._head == None:
               self._head = node
               return
           cur = self._head
           pre = None
           
           while cur:
               pre = cur
               cur = cur.next
           pre.next = node
       def travel(self):
           cur = self._head
           while cur:
               print(cur.item)
               cur = cur.next
       def remove(self,item):
           cur = self._head
           pre = None
           #删除的是第一个节点
           if cur.item == item:
               self._head = cur.next
               return
           while cur:
               pre = cur
               cur = cur.next
               if item == cur.item:
                   pre.next = cur.next
                   return
       
       def reverse(self):
           cur = self._head
           pre = None
           next_node = cur.next
           
           while cur:
               cur.next = pre
               pre = cur
               cur = next_node
               if cur:
                   next_node = cur.next
           self._head = pre
       
    # 双向链表就是连续开辟三个内存空间,分别存放 数据 上个节点内存地址 下个节点内存地址   
    

    二叉树

    • 二叉树
      • 根节点
      • 叶子节点:
        • 左叶子节点
        • 右叶子节点
      • 树的层级/树的高度
    • 二叉树的遍历
      • 广度优先遍历
        • 一层一层对节点进行遍历
      • 深度优先遍历
        • 前序:根左右
        • 中序:左根右
        • 后序:左右根

    # 使用python代码实现二叉树
    class Node():
        def __init__(self,item):
            self.item = item
            self.left = None
            self.right = None    
    class Tree():
        def __init__(self):
            self.root = None
        def addNode(self,item):
            node = Node(item)
            #如果插入第一个节点的情况
            if self.root == None:
                self.root = node
                return
            cur = self.root
            q = [cur] #列表元素是我们进行遍历判断的节点
            while q:
                nd = q.pop(0)
                if nd.left == None:
                    nd.left = node
                    return
                else:
                    q.append(nd.left)
                if nd.right == None:
                    nd.right = node
                    return
                else:
                    q.append(nd.right)
        def travel(self):  #广度优先遍历
            cur = self.root
            q = [cur]
            while q:
                nd = q.pop(0)
                print(nd.item)
                if nd.left:
                    q.append(nd.left)
                if nd.right:
                    q.append(nd.right)
                    
        def forwoar(self,root): #深度优先 前序:根左右
            if root == None:
                return
            print(root.item)
            self.forwoar(root.left)
            self.forwoar(root.right)
        def middle(self,root):  #深度优先 前序:左根右
            if root == None:
                return
            self.middle(root.left)
            print(root.item)
            self.middle(root.right)
        def back(self,root):   #深度优先 前序:左右根
            if root == None:
                return
            self.back(root.left)
            self.back(root.right)
            print(root.item)
    
    作 者:郭楷丰
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角 推荐一下。您的鼓励是博主的最大动力!
    自 勉:生活,需要追求;梦想,需要坚持;生命,需要珍惜;但人生的路上,更需要坚强。带着感恩的心启程,学会爱,爱父母,爱自己,爱朋友,爱他人。
  • 相关阅读:
    动态规划(下):如何求得状态转移方程并进行编程实现?
    SQL注入
    动态规划(上):如何实现基于编辑距离的查询推荐?
    XSS
    组合
    访问控制
    排列
    基于离散对数的签名方案
    基于RSA的签名方案
    centos7基于Hadoop的集群安装配置Hive
  • 原文地址:https://www.cnblogs.com/guokaifeng/p/12819778.html
Copyright © 2011-2022 走看看