Python數據結構初識:
一、Python數據結構概述
1.何爲數據結構
在程序中,同樣的一個或幾個數據組織起來,可以有不同的組織方式,也就是不同的存儲方式,不同的組織方式就是不同的結構,我們把這些數據組織在一起的結構就叫做數據結構
例如:
有一串字符串:"abc",我們將它重新組織一下,比如通過list()函數將"abc"變成["a","b","c"],那麼這個時候數據發生了重組,重組之後的結構就發生了變化,我們把["a","b","c"]這種結構叫做列表,也就是說列表是數據結構的一種類型之一。數據結構除了列表之外還有元組(),字典{"":"",}、隊列、棧、樹等。
2.數據結構實例
Python中的數據結構有很多類型。其中,Python中系統自己定義的不需要我們自己去定義的數據結構叫做Python的內置數據結構,比如列表、元組等,而有一些數據組織方式,Python系統裏面沒有直接定義,需要我們自己去定義這些數據的組織方式,這些組織方式稱爲Python的擴展數據結構,比如棧、隊列等。
#實例:
#Python內置的數據結構有元組、列表、字典等。
#現在有三個物品,分別是"apple","orange","pear",需要把這三個物品存儲起來
#存儲方式1:這三個物品每個物品按順序分別存儲到一個櫃子裏,這些物品可以取出來,如下:可以修改
["apple","orange","pear"]
#存儲方式2:這三個物品每個物品按順序分別存儲到一個櫃子裏,但是物品不可以取出來,也不可以放到其他櫃子,如下,其實就是不可修改
("apple","orange","pear")
#存儲方式3:這三個物品不僅按順序存儲到一個櫃子裏,而且每個櫃子還有一個名詞
{"sam":"apple","jac":"orange","mating":"pear"}
3.數據結構和算法的關係
在程序設計中,我們會發現數據結構經常和算法合在一起,這是爲什麼呢?其實,數據結構是數據的組織方式,就是存儲方式,也就是說,數據結構是靜態的。算法是指運算方法,通俗的說,就是運算思維,程序是動態的,需要將數據進行計算,運算方法有很多,不同的運算方法叫做不同的算法,所以我們可以這樣理解:數據結構是算法的基礎,但相同的數據結構運用不同的算法擁有不同的效率
二、Python常見數據結構-棧
1.何爲棧
棧是一種數據結構,這種數據結構不同於系統自帶的內置數據結構,屬於擴展數據結構,需要自己定義
特點:棧相當於一端開口一端封閉的容器,數據A可以存儲在棧裏面,把數據A移動到裏面這個過程叫做進棧,也叫壓棧、入棧
如果數據A到達棧頂後,同是佔了棧的一個位置,當再進入一個數據B的時候,也將到達棧頂,然後使A到棧頂的下一個位置,棧只能對棧頂的數據進行操作,此時就不能對A進行操作,可以將B出棧或刪除,等B出棧後,A變成棧頂的時候就可以對A進行操作
2.棧的圖示
只能從開口進開口出,棧頂指向新數據的位置,棧底不變,用過棧頂指針的移動進行數據的進棧出棧。
3.Python中棧的實現
棧是列表的擴展,只是棧只能從棧頂進行修改,不像列表可以從任意地方
#實例:
#棧的實現:
#棧是列表的擴展,只是棧只能從棧頂進行修改,不像列表可以從任意地方
class Stack(): #定義棧的類 def __init__(st,size): #初始化函數,兩個形參,一個代表主體,一個代表容 量 st.stack=[]; #聲明瞭棧 st.size=size; #聲明棧的容量 st.top=-1; #初始與棧底重合的棧頂 def push(st,content): #入棧定義 if st.Full(): print"Stack is Full" else: st.stack.append(content) #入棧,數據進入,append增加內容,調用 append方法 st.top=st.top+1 #棧頂指針加1 def out(st): if st.Empty(): print"Stack is Empty!" else: st.top=st.top-1 def Full(st): #判斷棧是否Full if st.top==st.size: return True #棧滿 else: return False def Empty(st): if st.top==-1: print"Stack is Empty!"
三、Python常見數據結構-隊列
1.何爲隊列
隊列也是一種擴展的數據結構
特點:兩端開的開口容器,但是只能在一端進行刪除操作,不能進行插入操作,而另一端只能進行插入操作而不能進行刪除操作,進行插入的這端叫做隊尾,進行刪除操作的這端叫做隊首
數據是隊尾進隊首出,類似於排隊
隊首隊尾不是根據位置來區別的,是根據功能來區分的
2.隊列的圖示
隊尾進隊首出
進隊:qu.tail=qu.tail+1
出隊:qu.head=qu.head+1
3.Python中隊列的實現
#隊列的實現 class Queue(): #隊列類 def __init__(qu,size): #初始化信息,隊列主體qu,隊列容量size qu.queue=[]; #用列表聲明 qu.size=size; #傳遞進來的參數信息 qu.head=-1; #剛開始的隊首隊尾都在輸出方 qu.tail=-1; def Empty(qu): #先判斷是否爲空 if qu.head==qu.tail: #空的時候隊首隊尾指針參數 return True else: return False def Full(qu): #判斷隊列是否已滿 if qu.tail-qu.head+1==qu.size: return True else: return False def enQueue(qu,content): #進隊 if qu.Full(): print "Queue is Full!" else: qu.queue.append(content) qu.tail=qu.tail+1 #進隊只和隊尾相關,隊尾指針加1 def outQueue(qu): #出隊 if qu.Empty(): print "Queue is Empty!" else: qu.head=qu.head+1 #出隊指針只和隊首相關,隊首加1
四、Python常見數據結構-樹
1.何爲樹:
樹是一種非線性的數據結構,樹具有非常高的層次性。利用樹來存儲數據,能夠是用公有元素進行存儲,能夠很大程度上節約空間。
定義:有且只有一個根節點,其次有N個不相交的子集,每個子集爲一顆子樹
2.樹的圖示:
3.什麼是二叉樹:
二叉樹市一中特殊的樹,二叉樹要麼是空樹,要麼是左、右兩個不相交的子樹組成,二叉樹是有序樹,即使只有一個子樹,也需要區分該子樹是左子樹還是右子樹。二叉樹每個節點的度不可能大於2,可以取0,1,2。二叉樹的存儲方式有兩種,一種是順序方式,一種是鏈式存儲。
順序存儲採用一維數組的存儲方式
鏈式存儲中,採用表的存儲方式,通常分爲三部分:數據域,左孩子鏈域和右孩子鏈域
4.二叉樹的圖示:
有5種情況,加上空樹
5.Python中樹以及二叉樹的實現:通過列表表示
#1.樹的基本構造
#樹通過逗號,隔開
#樹是由列表構成的,實際上Tree2=[58,6,[5]],Tree3=[5] Tree=[2,3,[58,6,[5]]] print Tree[0] print Tree[1] print Tree[2] Tree2=Tree[2] print Tree2[0] >>> 2 3 [58, 6, [5]] 58#實現了樹的嵌套,子樹 >>>
#2.二叉樹的構造
'''
比如要構造一個二叉樹:
7
8 9
23 36
57 58
可以這樣分析:
節點(左節點,右節點,當前節點數據)
根節點base=(-->8也就是jd2,-->9也就是jd3,base)
jd2=(no,-->23也就是jd4,8)
jd3=(no,-->36也就是jd5,9)
jd4=(-->57也就是jd6,-->58也就是jd7,23)
jd5=(no,no,36)
jd6=(no,no,57)
jd7=(no,no,58)
但是要注意,寫的時候倒過來寫,就是從右葉子開始寫,直到根節點
jd7=(no,no,58)
jd6=(no,no,57)
'''
class TRee(): #樹的初始化 def __init__(self,leftjd=0,rightjd=0,data=0): self.leftjd=leftjd; self.rightjd=rightjd; self.data=data; class Btree(): #二叉樹的初始化 def __init__(self,base=0): self.base=base def empty(self): if self.base is 0: return True else: return False def qout(self,jd): """前序遍歷,NLR,根左右""" if jd==0: return #沒有節點的話,原樣返回 print jd.data #先返回根節點的值 self.qout(jd.leftjd) #訪問左節點 self.qout(jd.rightjd) #訪問右節點 def mout(self,jd): """中序遍歷,LNR,左根右""" if jd==0: return self.mout(jd.leftjd) print jd.data self.mout(jd.rightjd) def hout(self,jd): """後序遍歷,LRN,左右根""" if jd==0: return self.hout(jd.leftjd) self.hout(jd.rightjd) print jd.data
>>> jd1=TRee(data=8) >>> jd2=TRee(data=9) >>> base=TRee(jd1,jd2,7) >>> x=Btree(base) #調用Btree >>> x.qout (x.base) #前序遍歷NLR根左右 7 8 9 >>> x.mout (x.base) #中序遍歷LNR左根右 8 7 9 >>> x.hout (x.base) #後序遍歷LRN左右根 8 9 7 >>>
五、Python常見數據結構-鏈表
1.何爲鏈表
鏈表也是一種數據結構,鏈表是一種非連續,非順序的存儲方式,鏈表由一系列節點組成,每個節點包括兩個部分,一部分是數據域,另一個部分是指向下一節點的指針域,鏈表可以分爲單向鏈表,單向循環鏈表,雙向鏈表,雙向循環鏈表。
單向鏈表:a可以指向b,但是b不能指向a
單向循環鏈表:表頭和表尾首尾相連,仍是單項
雙向鏈表:a可以指向b,b也可以指向a
雙向循環鏈表:首尾相連,可以順時針,也可以逆時針
2.鏈表的圖示
指針域:指向下一個節點的位置
節點之間是不相連的
3.Python中鏈表的實現
#鏈表的實現(單向鏈表) class jd(): #節點類,存儲數據 def __init__(self,data): #初始化 self.data=data self.next=None #最初的時候不指向 class Linklist(): #鏈表類,實現鏈表作用 def __init__(self,jd2): #初始化 self.head=jd2 #把jd2傳到表頭 self.head.next=None #下一個位置 self.tail=self.head #初始化表頭表尾重合 def add(self,jd2): #增加鏈表節點 self.tail.next=jd2 #將節點2賦值到鏈表尾 self.tail=self.tail.next def view(self): #查看鏈表的所有情況 jd2=self.head #表頭 linkstr="" #節點的數據,轉化成字符串,然後不斷累加 while jd2 is not None: #節點2不爲空,開始 if jd2.next is not None: #節點2下一個節點不爲空,開始遍歷 linkstr=linkstr+str(jd2.data)+"-->" #開始遍歷節點 else: linkstr+=str(jd2.data) jd2=jd2.next print linkstr #打印出鏈表linkstr
>>> jd1=jd(7) >>> jd2=jd("hello") >>> jd3=jd(8) >>> x=Linklist(jd1) >>> x.add (jd3) >>> x.add (jd2) >>> x.view () 7-->8-->hello >>>
六、Python常見數據結構-bitmap:通過數組表示
1.何爲bitmap
同樣,bitmap也是一種數據結構。bit指的是位,map指的是圖,bitmap也叫是位圖。這種數據結構的存儲簡單來說就是把原來的數轉化成二進制來存儲,每個位佔一個存儲單元。我們對bitmap進行數據操作時,也就相當於操作一個位。bitmap的數據結構的優點是可以實現很好的排序
2.bitmap的圖示
最高位爲符號位,Python中一個數是32位,最右邊爲最低位,位圖上存在數就變成1,不存在就是0
00000000 00000000 00000000 00000101
2^2+2^0=5,上面是數字5的二進制形式,實際上bitmap和二進制數值是有差異的
def bitIndex(self, num): #位索引,算出數值所在單元
return num % 31
3.Python中bitmap的實現
(1).bitmap排序原理:
例如:請比較1,2,34的大小(出去符號位最高位在左邊)
數組1:可以存儲31個數,除去符號位,範圍1-31
數組2:可以存儲31個數,除去符號位,範圍32-62
1:存儲到數組1,2^0
2:存儲到數組1,2^1
34:存儲到數組2,34-32=2,再加1,就是數組2第三位
首先:數組2的大於數組1,從右往左依次增大
開始時bitmap爲0,當所對應的位置存在數據時,就開始映射到bitmap對應位置,位置
上的0變成1
#(2).bitmap的實現 class Bitmap(): def __init__(self, max): #最大的數 self.size = int((max+31 - 1) / 31) #計算所需要的數組個數 self.array = [0 for i in range(self.size)] #從數組中開始生成單元, 每個單元存儲的值都是0 def bitIndex(self, num): #位索引,算出數值所在單元 return num % 31 def set(self, num): #置1 elemIndex =num / 31 #判斷所在數組 byteIndex = self.bitIndex(num) #計算位索引 elem= self.array[elemIndex] #對應選擇的數組 self.array[elemIndex] = elem |(1 << byteIndex) #置1,向左移動的次數 def test(self, i): elemIndex = i / 31 #判斷在第幾個數組 byteIndex = self.bitIndex(i) if self.array[elemIndex] & (1 << byteIndex): #判斷是否在bitmap,不應 該超出範圍 return True return False if __name__ == '__main__': MAX = ord('z') #設置最大數爲‘z’使用ord轉化成ansll suffle_array = [x for x in 'coledraw'] #將單詞拆分 result = [] bitmap = Bitmap(MAX) #將MAX傳遞到Bitmap for c in suffle_array: #從c開始調用到set bitmap.set(ord(c)) for i in range(MAX + 1): if bitmap.test(i): #如果存在i中存在數值,進行依次調用到test result.append(chr(i)) print '原始數組爲: %s' % suffle_array #拆分後的數組 print '排序後的數組爲: %s' % result
>>> =============================== RESTART =============================== >>> >>> 原始數組爲: ['c', 'o', 'l', 'e', 'd', 'r', 'a', 'w'] 排序後的數組爲: ['a', 'c', 'd', 'e', 'l', 'o', 'r', 'w'] >>>
七、Python常見數據結構-圖
1.何爲圖
圖仍是一種數據結構,我們可以簡單的理解成一個關係網絡,該網絡中有N多結點,每個結點都存儲着一個數據,數據之間的關聯我們可以用線把關聯的結點連起來的方式進行表示。
其中,有的數據關係是有方向的,比如數據A-->數據B,其關係只能從A到B,而不能從B到A,如果數據之間的關係是有方向,我們在圖裏面用帶箭頭弧線表示。有的數據關係是沒有方向的,A--B表示既可以從A關聯到B,也可以B關聯A,這種沒有方向的關係用線段表示。
2.圖的圖示
不同的結點之間有的有直接聯繫,有的通過中間結點有間接聯繫
3.Python中圖的實現
#圖的實現 chart={"A":["B","D"],"C":["E"],"D":["C","E"]}#圖通過字典表示 #"A":["B","D"]:A-->B,A-->D #"C":["E"]:C-->E #"D":["C","E"]:D-->C,D-->E def path(chart,x,y,pathd=[]): #chart:圖 #x:起始結點 #y:指向結點 #pathd=[]:走過的路徑 pathd=pathd+[x] #初始結點 if x==y: return pathd #返回pathd if not chart.has_key(x): #判斷是否存在結點 return None for jd in chart[x]: #結點在chart所直接對應的結點 if jd not in pathd: newjd=path(chart,jd,y,pathd) #初始結點變成jd,尋找路徑 if newjd: return newjd #找到新結點的時候返回值
>>> =============================== RESTART =============================== >>> >>> path(chart,"A","E") ['A', 'D', 'C', 'E'] >>>
與之共勉,入門學習,需要持之以恆。