數據結構是指相互之間存在着一種或多種關係的數據元素的集合和該集合中數據元素之間的關係的組成。python
數據結構就是設計數據以何種方式存儲在計算機中,列表、字典等都算是數據結構。linux
程序=數據結構+算法,數據結構屬於靜態的部分,算法的調用爲動態部分算法
根據邏輯結構劃分:數據庫
python中的列表和其餘語言中的數組很類似,區別爲:編程
append操做會不會使速度變慢?數組
老是能聽到一個詞 堆棧 ,堆(heap)和棧(stack)是兩個東西,傳統的編程語言中把內存分爲兩個地方,堆空間和棧空間,堆存儲的是一些動態生成的對象,與數據結構中的堆是不一樣的,棧空間由系統調用,存放函數的參數值,局部變量的值。
應該是早年間翻譯的問題,通常聽到堆棧指的就是棧。安全
#棧的python實現 class Stack: def __init__(self,size): self.size=size self.top = 0 self.lst=[] def push(self,a): if self.top = self.size: raise StackFullError("stackoverflow") self.lst.insert(self.top,a) self.top+=1 def pop(self): if self.top = 0: raise StackEmptyError() b = self.list[self.top] self.lst.pop(self.top) returm b
def brace_match(s): stack = [] d ={'(':')','[':']','{':'}'} for ch in s: if ch in {'(','[','{'}: stack.append(ch) elif len(stack)==0: print('多了%s' %ch) return False elif d[stack[-1]] == ch: stack.pop() else: print('%s不匹配'%ch) if len(stack)==0: return True else: print("未匹配") return False
隊列是一個數據集合,僅容許在列表的一端插入,另外一端刪除。數據結構
因爲數組定長,不能繼續添加數據,若是是列表,出隊的操做就會出現空位,因此想辦法讓數組變成一個圓環。app
class queue: def __init__(self, capacity = 10): self.capacity = capacity self.size = 0 self.front = 0 self.rear = 0 self.array = [0]*capacity def is_empty(self): return 0 == self.size def is_full(self): return self.size == self.capacity def enqueue(self, element): if self.is_full(): raise Exception('queue is full') self.array[self.rear] = element self.size += 1 self.rear = (self.rear + 1) % self.capacity def dequeue(self): if self.is_empty(): raise Exception('queue is empty') self.size -= 1 self.front = (self.front + 1) % self.capacity def get_front(self): return self.array[self.front]
class queue: def __init__(self,size): self.a = [] self.b = [] self.size = size def popleft(self): if not self.b and self.b is None: el = self.b.pop(-1) self.append(el) self.a.pop(-1) else: raise Exception("empty") def append(self,item): if self.b<self.size: self.b.append[item] else: raise Exception("FUll")
import queue #涉及線程安全用queue from collections import deque #經常使用解題的用deque q = deque() #是一種雙向隊列,popleft出隊 #模擬linux命令 head和tail,假如是tail 5 deque(open('a.text','r',encooding='utf8'),5) #創建一個定長的隊列,當隊列滿了以後,就會刪除第一行,繼續添加
鏈表就是非順序表,與隊列和棧對應。編程語言
鏈表中每個元素都是一個對象,每一個對象稱爲一個節點,包含有數據域key和指向下一個節點的next,經過各個節點之間的相互鏈接,最終串聯成一個鏈表。
頭節點爲空也是爲了表示空鏈表,也叫作帶空節點的鏈表,頭節點也能夠記錄鏈表的長度
class Node(object): def __init__(self,item): self.data=data self.next=None #eg a=Node(1) b=Node(2) c=Node(3) a.next=b b.next=c #鏈表的最後一個節點的next就爲None
class LinkList: def __init___(self,li,method='tail'): self.head = None self.tail = None if method == 'head': self.create_linklist_head(li) if method == 'tail' self.create_linklist_tail(li) else: rais ValueError('unsupport') #頭插法 def create_linklist_head(self,li): self.head = Node(0) for v in li: n = Node(v) n.next = self.head.next #當插入下一個元素時,應該與下一個節點鏈接後再跟頭節點鏈接 self.head.next = n self.head.data += 1 #尾插法 def create_linlist_tail(self,li): #不斷更新尾巴 self.head = Node(0) self.tail = self.head for v in li: p = Node(v) self.tail.next = p self.tail = p self.head.data += 1 #鏈表的遍歷輸出 def traverse_linlist(self): p = self.head.next while p: yield p.data p = p.next
#p表示待插入節點,curNode表示當前節點 p.next = curNode.next #不能當前鏈接直接斷開 curNode,next = p
p = curNode.next curNode.next = p.next del p #不寫也同樣,引用計數,python的內存回收機制
雙鏈表中每一個節點有兩個指針:一個指向後面節點、一個指向前面節點。
節點定義:
class Node(object): def __init__(self, item=None): self.item = item self.next = None self.prior = None
p.next = curNode.next curNode.next.prior = p p.prior = curNode curNode.next = p
p = curNode.next curNode.next = p.next p.next.prior = curNode del p
鏈表與列表相比
哈希表就是直接尋址表的改進。當關鍵字的全域U比較小時,直接尋址是一種簡單有效的方法。
哈希表是一個經過哈希函數計算數據存儲位置的線性表的存儲結構,又叫作散列表。
h(k)= k mod m
h(k) = floor(m(KA mod 1)) 0<A<1
class HashTable: def __init__(self): self.size=11 self.slots=[None]*self.size self.data=[None]*self.size def hash_function(self,key,size): return key%size def rehash(self,old_hash,size): return (old_hash+1)%size def put(self,key,data): hash_value=self.hash_function(key,len(self.slots)) if self.slots[hash_value]==None: self.slots[hash_value]=key self.data[hash_value]=data else: next_slot=self.rehash(hash_value,len(self.slots)) while self.slots[next_slot]!=None and\ self.slots[next_slot]!=key: next_slot=self.rehash(next_slot,len(self.slots)) if self.slots[next_slot]==None: self.slots[next_slot]=key self.data[next_slot]=data else: self.data[next_slot]=data def get(self,key): start_slot=self.hash_function(key,len(self.slots)) data=None stop=False found=False position=start_slot while self.slots[position]!=None and not found and not stop: if self.slots[position]==key: found=True data=self.data[position] else: position=self.rehash(position,len(self.slots)) if position==start_slot: stop=True return data def __getitem__(self,key): return self.get(key) def __setitem__(self,key,data): self.put(key,data)
因爲哈希表的大小是有限的,而要存儲信息的數量是無限的,所以,對於任何哈希函數,都會出現兩個元素映射到同一個位置的狀況,這種狀況就叫作哈希衝突。
解決哈希衝突的方法:
開放尋址法:若是哈希函數返回的位置已經有值,則能夠向後探查新的位置來儲存這個值。
p+1,p+2....
。p+1**2,p-1**2,p+2**2
。dic = {'name':'cui'} #能夠認爲是h('name')=1,則哈希表爲[None,'cui']
在堆排序時曾經介紹了什麼是二叉樹,當時是用列表來實現的,可是二叉樹可能出現空值,浪費空間,因此使用相似鏈表的存儲結構。
class BiTreeNode: def __init__(self,data): self.data=data self.lchild=None self.rchild=Node
二叉樹的遍歷有兩類四種:
#前序遍歷,root爲根節點 def pre_order(root): if root: print(root.data,end = '') pre_order(root.lchild) pre_order(root.rchild) #中序遍歷,若是lchild沒值則出棧 def in_order(root): if root: pre_order(root.lchild) print(root.data,end = '') pre_order(root.rchild) #後序遍歷,若是rchild沒值則出棧 def post_order(root): if root: pre_order(root.lchild) pre_order(root.rchild) print(root.data,end = '')
#根據隊列實現 def level_order(root): q=deque() q.append(root) while(len(q)>0): x=q.popleft() print(x.data,end='') if x.lchild(): q.append(x.lchild) if x.rchild(): q.append(x.rchild)
二叉搜索樹,也叫二叉排序樹,它要求每個節點左子樹的節點都比它小,右子樹的節點都比他大。
class BST: def __init__(self): self.root=None #空不是根節點 而是None def insert(self,key): if not self.root: self.root = BiTreeNode(key) else: p=self.root while p: if key < p.data: #分爲左子樹是否爲空的狀況 if p.lchild: #左子樹有節點就在左子樹繼續查找,不然就插入左節點的位置 p = p.lchild else: p.lchild = BiTreeNode(key) elif key > p.data: if p.rchild: p = p.rchild else: p.lchild = BiTreeNode(key) break else: break
def query(self,key): p = self.root while p : if key < p.data: p = p.lchild elif key >p.data: p=p.rchild else: return True return False
刪除有三種狀況:
平均狀況下,二叉搜索時的時間複雜度爲O(logn),可是二叉搜索樹可能會出現偏斜的狀況,須要採用隨機打亂的方法,因此這時候採用AVL樹(自動平衡樹)。
相關知識點:
AVL樹:AVL樹是一棵自平衡的二叉搜索樹,它具備如下性質:
插入一個節點可能會形成AVL樹的不平衡,能夠經過旋轉操做來修正。
插入一個節點後,只有從插入節點到根節點的路徑上的節點的平衡可能被改變,須要找到第一個平衡條件的節點,稱之爲K,K的兩棵子樹高度差確定爲2.
不平衡的出現有四種狀況:
B-Tree是一種自平衡的多路搜索樹,B-Tree存儲在硬盤裏,用於數據庫的索引。