鏈表|棧|隊列|樹(Python實現)

鏈表


(單鏈表 雙鏈表 循環鏈表)只是一個定義的結構而已 (數據結構不一樣而已)
具體的對這個定義的操作要到這個定義實現的類當中去調用而已
在這裏插入圖片描述
概念區分

  • 頭結點:是爲了方便操作鏈表而附設的,頭結點數據域通常用來保存跟鏈表有關的信息,比如鏈表的長度;

  • 首元結點:就是鏈表裏“正式”的第一個結點,即鏈表的開始結點。形如a1,a2,a3,…an;

  • 頭指針:頭指針是指向鏈表的基地址。如果鏈表存在頭結點則頭指針就是指向頭結點的地址,反之指向首元結點的地址。

#定義節點類型
class Node(object):
   def __init__(self,elem,next_=None):
       self.elem=elem
       self.next=next_

#定義單鏈表
class Linklist(object):
   def __init__(self,none=None):
       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.elem,end=" ")
           cur =cur.next
       #輸出一個換行
       print('')
   #首部加元素
   def add(self,item):
       #將數據轉換爲節點類型
       node=Node(item)
       #新的節點指向首元節點
       node.next=self.head
       #新的節點變成首元節點
       self.head=node
   #尾部加元素
   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 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.next=cur.next
           cur.next=node
   #刪除指定值的節點
   def remove(self,item):
       cur=self.head
       pre=None
       while cur != None:
           if cur.elem==item:
               #如果當前節點的值符合要求
               if cur==self.head:
                   #如果符合的節點是首元節點
                   self.head=cur.next
                   break
               else:
                   #從當前節點的前一個節點直接指向當前節點的下一個節點
                   pre.next=cur.next
                   break
           else:
               #當前節點不符合
               pre=cur#記錄當前節點的位置
               cur=cur.next
       #查詢某個值是否存在
   def search(self,item):
       cur=self.head
       while cur!=None:
           if cur.elem==item:
               return True
           else:
               cur=cur.next
       return False

if __name__=='__main__':
   linklist=Linklist()
   for i in range(5):
       linklist.append(i)
   linklist.travel()
   linklist.insert(3,7)
   linklist.travel()
   print(linklist.search(4))
   linklist.remove(7)
   linklist.travel()

特點:插入和刪除操作只能在一個位置進行的表,該位置是表的末端,稱爲棧的頂(top)。
先進後出

具體操作

  • Stack() 創建一個新的空棧
  • push(item) 添加一個新的元素item到棧頂
  • pop() 彈出棧頂元素
  • peek() 返回棧頂元素
  • is_empty() 判斷棧是否爲空
  • size() 返回棧的元素個數
"""
Stack() 創建一個新的空棧
push(item) 添加一個新的元素item到棧頂
pop() 彈出棧頂元素
peek() 返回棧頂元素
is_empty() 判斷棧是否爲空
size() 返回棧的元素個數
"""
class Stack(object):
    def __init__(self):
        self.items=[]
    def is_empty(self):
        return self.items==[]
    #入棧
    def push(self,item):
        self.items.append(item)
    #彈出棧頂
     def pop(self):
        if self.is_empty():
            raise IndexError
        self.items.pop()
    #返回棧頂元素
    def peek(self):
        return self.items[self.size()-1]
    #獲取棧長度
    def size(self):
        return len(self.items)


if __name__=='__main__':
    stack=Stack()
    for i in range(0,10):
        stack.push(i)
    print(stack.size())
    print(stack.is_empty())
    print(stack.peek())
    stack.pop()
    print(stack.peek())

隊列

特點:插入和刪除在不同的端進行。隊列的基本操作是Enqueue(入隊),在表的末端(rear)插入一個元素,還有出列(Dequeue),刪除表開頭的元素。
先進先出.

"""
Queue() 創建一個新的空棧
enqueue(item) 添加一個新的元素item到隊列底部
delqueue() 彈出隊首元素
is_empty() 判斷隊列是否爲空
size() 返回隊列的元素個數
"""
class Queue(object):
    def __init__(self):
        self.queues=[]
    def is_empty(self):
        return self.queues==[]
    def enqueue(self,queue):
        self.queues.append(queue)
    def delqueue(self):
        if self.is_empty():
            raise IndexError
        val=self.queues[0]
        self.queues.remove(val)
        return val
    def size(self):
        return len(self.queues)
if __name__=='__main__':
    queue=Queue()
    print(queue.is_empty())
    for i in range(10):
        queue.enqueue(i)
    print(queue.size())
    print(queue.delqueue())
    print(queue.delqueue())

(英語:tree)是一種抽象數據類型(ADT)或是實作這種抽象數據類型的數據結構,用來模擬具有樹狀結構性質的數據集合。它是由n(n>=1)個有限節點組成一個具有層次關係的集合。把它叫做“樹”是因爲它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點:

  • 每個節點有零個或多個子節點;
  • 沒有父節點的節點稱爲根節點;
  • 每一個非根節點有且只有一個父節點;
  • 除了根節點外,每個子節點可以分爲多個不相交的子樹;

樹的術語

  • 節點的度:一個節點含有的子樹的個數稱爲該節點的度;
  • 樹的度:一棵樹中,最大的節點的度稱爲樹的度;
  • 葉節點或終端節點:度爲零的節點;
  • 父親節點或父節點:若一個節點含有子節點,則這個節點稱爲其子節點的父節點;
  • 孩子節點或子節點:一個節點含有的子樹的根節點稱爲該節點的子節點;
  • 兄弟節點:具有相同父節點的節點互稱爲兄弟節點;
  • 節點的層次:從根開始定義起,根爲第1層,根的子節點爲第2層,以此類推;
  • 樹的高度或深度:樹中節點的最大層次;
  • 堂兄弟節點:父節點在同一層的節點互爲堂兄弟;
  • 節點的祖先:從根到該節點所經分支上的所有節點;
  • 子孫:以某節點爲根的子樹中任一節點都稱爲該節點的子孫。
  • 森林:由m(m>=0)棵互不相交的樹的集合稱爲森林;

樹的種類

  • 無序樹:樹中任意節點的子節點之間沒有順序關係,這種樹稱爲無序樹,也稱爲自由樹;
  • 有序樹:樹中任意節點的子節點之間有順序關係,這種樹稱爲有序樹;
  • 二叉樹:每個節點最多含有兩個子樹的樹稱爲二叉樹;
  • 完全二叉樹:對於一顆二叉樹,假設其深度爲d(d>1)。除了第d層外,其它各層的節點數目均已達最大值,且第d層所有節點從左向右連續地緊密排列,這樣的二叉樹被稱爲完全二叉樹x
  • 滿二叉樹:所有分支節點的度都是2
  • 平衡二叉樹(AVL樹):當且僅當任何節點的兩棵子樹的高度差不大於1的二叉樹;
  • 排序二叉樹(二叉查找樹(英語:Binary Search Tree),也稱二叉搜索樹、有序二叉樹);
  • 霍夫曼樹(用於信息編碼):帶權路徑最短的二叉樹稱爲哈夫曼樹或最優二叉樹;
  • B樹:一種對讀寫操作進行優化的自平衡的二叉查找樹,能夠保持數據有序,擁有多餘兩個子樹。

樹的存儲與表示

順序存儲:將數據結構存儲在固定的數組中,然在遍歷速度上有一定的優勢,但因所佔空間比較大,是非主流二叉樹。二叉樹通常以鏈式存儲。

常見的一些樹的應用場景

  1. xml,html等,那麼編寫這些東西的解析器的時候,不可避免用到樹
  2. 路由協議就是使用了樹的算法
  3. mysql數據庫索引
  4. 文件系統的目錄結構
  5. 所以很多經典的AI算法其實都是樹搜索,此外機器學習中的decision tree也是樹結構
#定義樹的節點
class Node(object):
    def __init__(self,item):
        self.elem=item
        self.lchild=None
        self.rchild=None

#定義樹
class Tree():
    def __init__(self):
        self.root=None
    #添加樹
    def add(self,item):
        node=Node(item)
        if self.root==None:
            #如果根節點爲空
            self.root=node
        else:
            queue=[]
            queue.append(self.root)
            while queue:
                cur_node=queue.pop(0)
                #取出列表第一個元素額
                if cur_node.lchild is None:
                    cur_node.lchild=node
                    return
                else:
                    #如果當前節點的左子樹不爲空將其添加至列表中
                    queue.append(cur_node.lchild)
                if cur_node.rchild is None:
                    cur_node.rchild =node
                    return
                else:
                    queue.append(cur_node.rchild)

    #廣度遍歷非遞歸
    def breadth_travel(self):
        if self.root==None:
            return
        queue=[]
        queue.append(self.root)
        while queue:
            node=queue.pop(0)
            print(node.elem,end=' ')
            if node.lchild!=None:
                queue.append(node.lchild)
            if node.rchild!=None:
                queue.append(node.rchild)
        print('')

    def breadth_travel_two(self):
        if self.root==None:
            return
        queue=[]
        queue.append(self.root)
        while queue:
            length=len(queue)
            for i in range(length):
                node=queue.pop(0)
                print(node.elem,end=' ')
                if node.lchild != None:
                    queue.append(node.lchild)
                if node.rchild != None:
                    queue.append(node.rchild)
        print('')

    #深度遍歷 非遞歸 前序遍歷 根 左 右
    def deep_travel_qianxu(self):
        if self.root==None:
            return
        queue=[]
        queue.append(self.root)
        while queue:
            cur=queue.pop()
            print(cur.elem,end=' ')
            #前序遍歷 根 左 右
            #先放入右節點再放入作節點
            if cur.rchild is not None:
                queue.append(cur.rchild)
            if cur.lchild is not None:
                queue.append(cur.lchild)
        print('')
    #左根右
    """
    1. 使用一個棧保存結點(列表實現);
    2. 如果結點存在,入棧,然後將當前指針指向左子樹,直到爲空;
    3. 當前結點不存在,則出棧棧頂元素,並把當前指針指向棧頂元素的右子樹;
    4. 棧不爲空,循環2、3。
    """
    def deep_travel_zhongxu(self):

        if not self.root:
            return
        stack = []
        cur=self.root
        while cur or stack:
            #將當前節點的左節點都入棧
            while cur:
                stack.append(cur)
                cur = cur.lchild
            # 獲取當前最左節點
            if stack:
                a = stack.pop()
                cur = a.rchild
                print(a.elem,end=' ')
        print('')
    #左 右 根
    def deep_travel_houxu(self):
        cur=self.root
        stack = [cur]
        stack2 = []
        while len(stack) > 0:
            cur = stack.pop()
            stack2.append(cur)
            if cur.lchild:
                stack.append(cur.lchild)
            if cur.rchild:
                stack.append(cur.rchild)
        while len(stack2) > 0:
            node = stack2.pop()
            print(node.elem,end=' ')

        print('')

    #深度遍歷遞歸
    def preorder(self, node):
        # 先序遍歷 根 左 右
        if node == None:
            return
        print(node.elem, end=" ")
        self.preorder(node.lchild)
        self.preorder(node.rchild)

    def inorder(self, node):
        # 中序遍歷 左 根 右
        if node == None:
            return
        self.inorder(node.lchild)
        print(node.elem, end=" ")
        self.inorder(node.rchild)

    def proorder(self, node):
        # 後序遍歷 左 右 根
        if node == None:
            return
        self.inorder(node.lchild)
        self.inorder(node.rchild)
        print(node.elem, end=" ")

if __name__=='__main__':
    tree=Tree()
    for i in range(7):
        tree.add(i)
    tree.breadth_travel_two()
    print("*"*20)
    tree.deep_travel_qianxu()
    print("*" * 20)
    tree.deep_travel_zhongxu()
    print("*"*20)
    tree.deep_travel_houxu()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章