資料結構與演算法
python佇列queue
詳見python3自定義比較器
python比較器
Python heapq 自定義比較器
#自定義比較器
#1. 對list等有key引數的
##二維陣列等的比較排序
list1.sort(key = lambda x: x[1])
##list中放置其他資料型別
import functools
#cmp的返回值為負數,第一個數在第二個數前面
#cmp的返回值為正數,第二個數在第一個數前面
def cmp(s1, s2):
pass
list1.sort(key = functools.cmp_to_key(cmp))
#2. 佇列操作
import queue
q = queue.Queue()
q.put()
q.get()
#3.優先順序佇列
qp = queue.Priorityqueue()
qp.put()#通常為一個(2,)的資料,第一位為優先順序,越小越優先,第二位為放入的資料項
#4.堆的操作
import heapq
heap = []
heapq.heappush(heap, list_data)#第一種把heap初始化為小根堆
heapq.heapify(list_data)#第二種
heapq.heappop(0)#彈出根節點
四大邏輯結構:集合結構,線性結構,樹形結構,圖形結構
物理結構:順序儲存(地址連續), 鏈式儲存(更靈活)
演算法效率
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2)
1. 排序
選擇排序
思想: 依次找到最小值放到最前面 時間複雜度O(n^2),空間複雜度O(1)
//(0 ----N-1)位置找到min放到0位置
//(1------N-1) 位置找到min放到1位置
氣泡排序
思想:(0 ---N-1)相鄰兩個比較,max往右移動;(0--N-2)相鄰兩個比較,max右移
// 1 2 3 4 5 6
// 1 2 位置誰大誰往右移
// 2 3 位置上誰大誰往右移
// 3 4 位置上誰大誰往右移
插入排序
思想:保證0-1有序,保證0-2有序,保證0-3有序,如果i位置比i-1位置小,交換,直到i不比i-1位置小。
def xuanze(arr):#選擇排序
for i in range(len(arr)):
for j in range(i+1, len(arr)):
# print(i)
if arr[j] < arr[i]:
arr[i], arr[j] = arr[j],arr[i]
return arr
def maopao(arr):#氣泡排序
for i in range(len(arr)):
for j in range(len(arr) -1-i):
if arr[j] > arr[j+1]:
arr[j+1], arr[j] = arr[j], arr[j+1]
return arr
def charu(arr):#插入排序
for i in range(1, len(arr)):
now = i
for j in range(i-1, -1, -1):
global bigo
bigo += 1
if arr[now] < arr[j]:
print(str(now)+'位置換到'+str(j)+'位置去')
arr[now], ar r[j] = arr[j], arr[now]
now = j
else:
break
global bigo#用於檢視到底進行了幾次
bigo = 0
arr = [1,2,3,4,6,0]
print(arr)
charu(arr)
print(arr)
print(bigo)
二分(logn)
遞迴做
arr = [1,2,3,4,5,6]
def erfeng(arr, num, L, R):
print('again')
if L == R:
pass
mid = int(L +(R-L)/2)
if num < arr[mid]:
R = mid
erfeng(arr, num, L, R)
elif num > arr[mid]:
L = mid +1
erfeng(arr,num, L,R)
else:
print('zhaodaol')
print(arr[mid])
L = 0
R = len(arr)
erfeng(arr, 1, L, R)
有序數列找比x小的最左側數
arr = [1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6]
def erfengzuo(arr, num, L, R, t):#first, t = R
print('now is %d, %d'%(L, R))
mid = int(L + (R - L)/2)
if arr[mid] >= num:
if L == mid:
raise IndexError
if t> mid:
t = mid
R = mid
erfengzuo(arr, num, L, R, t)
elif arr[mid]< num:
L = mid +1
erfengzuo(arr, num, L, R, t)
else:
print(arr[mid])
erfengzuo(arr, 3,0, len(arr), len(arr))
還有 無序陣列上找區域性最小的問題(畫出來,思維很簡單)
對數器 可以提供類似OJ的效果
random() [0,1) 等機率返回一個小數
int(random()*N) 等機率返回一個[0, N) 上的隨機整數
快速排序(荷蘭國旗問題)
給定陣列arr, 和一個數num,把小於num的數放在陣列左邊,大於num的數放在陣列右邊,時間複雜度為O(n),空間複雜度為O(1).
升級: 一個陣列,左邊小於num, 中間== num, 右邊大於num
思維誤區:三個指標, 小於區的右邊界,等於區的右邊界*** 等於區的右邊界其實是大於區的左邊界***
時間複雜度O(N * logn), 空間複雜度O(logn)
import random
def kuaisu(arr, L, R):
if L< R: #注意判斷條件!!!使用(2,2,3)試一試
random_num = int(random.random()*(len(arr)-1))#轉化為int型別!!!
print('前arr%s'% arr)
num = arr[random_num]
print('num: arr的第%d 個數,num為%d' % (random_num, num))
small, big = equalok(arr,num,L, R)
print('small:%d; big:%d'% (small, big))
print('L :%d; R :%d'%(L, R))
print('後arr%s'% arr)
kuaisu(arr, L, small)
kuaisu(arr, big, R)
def equalok(arr, num, L, R):
small = L-1#注意邊界問題i的取值是L開始的
big = R +1
i = L
while(i != big):
if arr[i]< num:
arr[i], arr[small +1] = arr[small +1], arr[i]
i += 1
small += 1
elif arr[i]> num:
arr[i], arr[big -1] = arr[big-1], arr[i]
big -= 1
elif arr[i] == num:
i +=1
return small, big
arr = [1,23,3,4,2]
kuaisu(arr, 0, len(arr)-1)
print(arr)
2. 遞迴
master公式 T(N) = a* T(N/b) + o(N^d)
while : a 子問題呼叫次數, N/b 子問題規模, o(N^d) 處理遞迴外的其他複雜度
log(b,a)< d 為O(N^d)
log(b, a) > d 為 O(N^(log(a,b)))
log(b, a) = d 為O( N^d * logn)
歸併排序
經典問題
時間複雜度 : O(N * logN)
注意點:如果a = [0,1], mid = 0, 列印a[L, mid] 結果為None
def merge(arr, L, R):
if L+1 == R:
print(L, end = ' ')
print(R)
if arr[L] > arr[R]:
arr[L], arr[R] = arr[R], arr[L]
return arr
elif L ==R:#注意對只有1個和2個元素時的處理方式
return arr
else:
mid = int(L + (R-L)/2)#mid一定要轉為整形
merge(arr, L, mid)
merge(arr, mid +1, R)
arr[L: R+1] = togother(arr, L, R, mid)
return arr
def togother(arr, L, R, mid):
p1 = L
p2 = mid+1
help1 = []
while( p1< mid +1 and p2 < R +1):#注意剩餘幾個元素的拉去條件
if arr[p1]< arr[p2]:
help1.append(arr[p1])
p1 += 1
else:
help1.append(arr[p2])
p2 += 1
if p1 == mid+1 :
help1.extend(list(arr[p2:R+1]))
if p2 == R+1:
help1.extend(list(arr[p1:mid+1]))
return help1
arr = [1,3,6,4,9,4,0,23,3]
arr = merge(arr, 0, len(arr)-1)
print(arr)
求小和問題
( 1,3,4,2,5)求每個數左邊比這個數小的和
:在一個陣列中,每一個數左邊比當前數小的數累加起來,叫做這個陣列的小和
注意點:思維轉化,把比某個數左邊小的數總和,變為某個數右邊有多少個比它大的
逆序對問題:在一個陣列中,左邊的數如果比右邊的數大,則這兩個數構成一個逆序對。求所有的逆序對。
思維同樣轉換為上述。
小和問題程式碼:
#1.134和25合併時,左邊的小和已經計算過了,所以只需要管右邊的就可以
# 某個數不會和自己所在的組產生小和;
#2. 當左右資料相同時,先把右邊的merge進去。
global he
he = 0
def xiaohe(arr, L, R):
if L + 1 == R:
if arr[L]> arr[R]:
arr[L], arr[R] = arr[R], arr[L]
elif arr[L] == arr[R]:
pass
else:
global he
he += arr[L]
print('two merge:%d'% he)
return arr
elif L == R:
return arr
else:
mid = int(L + (R-L)>>1)
xiaohe(arr, L, mid)
xiaohe(arr, mid+1, R)
print('left : %s'% arr[L:mid+1], end = ' ')
print('right: %s'% arr[mid+1: R+1])
arr[L:R+1] = togother(arr, L, mid, R)
print('merge: %s' % arr[L:R+1])
return arr
def togother(arr, L, mid,R):
p1 = L
p2 = mid+1
help1 = []
while(p1<mid+1 and p2< R+1):
if arr[p1]<arr[p2]:
help1.append(arr[p1])
global he
he += (arr[p1] * (R - p2+1))
print('p1: %d, p2:%d, 乘數:%d'%(p1, p2, (R-p2 +1)))
print('all merge: %d'% he)
p1 +=1
else: #if arr[p1]>=arr[p2]:
help1.append(arr[p2])
p2 += 1
while(p1 == mid +1) :
help1.extend(list(arr[p2:R+1]))
p1 += 1
print('?')
while(p2 == R +1):
help1.extend(list(arr[p1: mid +1]))
p2 += 1
print('?')
return help1
arr = [1,3,4,2,5]
arr = xiaohe(arr, 0, len(arr)-1)
print(he)
print(arr)
3. 堆
堆結構就是用陣列實現的完全二叉樹結構,堆中的某個節點總是不小於或不大於其父節點的值。
一個陣列從0開始,連續的一段可以構成完全二叉樹
特性 :1.連續的長度用size表示
- i位置的左孩子為: 2 * i +1; i 位置的右孩子為 2 * i + 2;當 這個值比size小時;
- i 位置的父節點為: int((i -1)/ 2 ) # 包括0節點
大根堆:完全二叉樹中,如果每棵子樹的最大值都在頂部;小根堆:完全二叉樹的每棵子樹的最小值都在頂部
heapinsert操作和 heapify操作,以及堆排序
堆排序思想:
- 把陣列arr變成一個堆
- 把跟節點和最後一個數交換,pop出來,heapsize --, 直到heapsize = 0.
時間複雜度: [........|........],如果有2N個元素,後面N個排序最差需要logN次, 共N個,所以是N*(logn)
#堆排序和兩個操作
def heapinsert(arr, index):
while(arr[index]> arr[int((index -1)/2)]):
arr[index], arr[int((index - 1)/2)] = arr[int((index -1)/2)], arr[index]
index = int((index -1)/2)
def heapify(arr, index, heapsize):
left = 2 * index + 1
while(left < heapsize):
max_num = left+1 if left+1 < heapsize and arr[left + 1] > arr[left] else left
max_num = max_num if arr[index] < arr[max_num] else index
if (max_num == index):
break
arr[index], arr[max_num] = arr[max_num], arr[index]
index = max_num
left = 2 * index +1
def heapsort(arr):
for i in range(len(arr)-1):
heapinsert(arr, i)
print(arr)
heapsize = len(arr)
arr[0], arr[len(arr) - 1] = arr[len(arr) - 1], arr[0]
heapsize -=1
heapify(arr, 0, heapsize)
while(heapsize > 0):
arr[0], arr[heapsize - 1] = arr[heapsize - 1], arr[0]
heapsize -= 1
heapify(arr, 0, heapsize)
arr = [1,3,2,6,5,8,3,5]
heapsort(arr)
print(arr)
擴充套件
已知一個幾乎有序的陣列,(每個元素的移動距離不超過k)選擇
import heapq#直接使用以及有的庫,庫預設為小根堆
def distancelessk(arr, k):
heap = []
for i in range(k+1):
heapq.heappush(heap, arr[i])
index = 0
while(index+k +1 < len(arr)):
arr[index] = heapq.heappop(heap)
heapq.heappush(heap, arr[index+k + 1])
index += 1
for i in range(k+1):
arr[index] = heapq.heappop(heap)
#print(arr[index])
index += 1
arr= [2,3,1,5,6,4,7,9,8]
distancelessk(arr, 2)
print(arr)
heapq中 大根堆的實現:heappush()的時候,填入資料*-1, heappop()的時候, 出來的資料 * -1
比較器
比較器的實質就是過載比較運算子
詳見python3自定義比較器
python比較器
自定義比較器返回值為負數, 第一個引數在前面
返回值為正數,第二個數排前面(升序排列)自己修改
在sort函式中新增排序的策略,可以實現自己的比較器
之前的排序都是基於兩個數的比較進行的
不基於比較的排序:只有很窄的應用範圍,
4. 桶排序
不基於比較的排序,有條件限制
記數排序
eg_-1: 員工年齡排序,構建一個[16, ....., 100]的陣列,遇到某個歲數,某個歲數++,遍歷一遍後,得到員工年齡詞頻統計表, 得到排序。
基數排序[17, 13, 25, 100, 72]
補全最高位的0, 按照最後一位數字進桶(桶是佇列,先進先出)
匯出桶中數字:
[100, 072, 013, 025, 017]
按照第二位進桶
0: 100,
1:013, 017
2:025
7:072
出桶: [100, 013, 017, 025 ,072]
按照第三位進桶:
0:013, 017, 024, 072
1: 100
出桶: [13, 17, 24, 7, 100]
5. 排序演算法彙總
排序穩定性: 指相同的元素再每次排序後是否能保持相同的位置(相同元素的相對次序)
eg: arr1[]:對商品價格從小到大排序
arr2[]: 基於上述排序對好評率從小到大排序,若能保持上述資料的排序基礎,則很有價值(體現排序的穩定性)
6個排序穩定性: 堆排,快排
快排最常用(常數項最低,所以最快一般),有空間要求選堆排,有穩定性要求選歸併
- 基於比較的時間複雜度最低N*logn
- 時間複雜度最低,空間複雜度小於N,則不能實現穩定性
排序的改進:
- 大規模時候採用N*logn的排序排程演算法,小範圍用N^2的演算法比較快
- 穩定性考慮
6. 雜湊
- 如果只有Key,沒有value,使用Hashset結構;key-value對,用hashmap結構
- 雜湊操作複雜度為常數項,但常數比較大。
- key值為基礎型別(int,string...),則直接複製;key值為自定義型別(類),則為自定義型別的記憶體地址
7. 連結串列
題目:
-
單連結串列雙連結串列 反轉(換頭帶返 回值,否則不帶)
-
列印兩個有序連結串列的公共部分,給定兩個有序連結串列的頭指標h1,h2;
技巧: 1. 使用額外資料記錄結構(雜湊表);2. 快慢指標
-
判斷連結串列是否為迴文結構(前後對稱):遍歷進棧,pop的時候和原連結串列比較
-
給定一個單連結串列head,整數型別,給一個數pivot,將連結串列調整為做部分小於pivot,中間等於,右邊小於。
-
複製含有隨機指標節點的連結串列
-
兩個連結串列相交問題:給定兩個可能有環也可能無環的單連結串列,頭節點head1,head2,實現一個函式,如果兩個連結串列相交,返回相交的第一個節點,如果不相交,返回null
8. 二叉樹
class Node:
V value
Node left
Node right
-
用遞迴和非遞迴兩種方式實現二叉樹的先序、中序、後序遍歷,
-
直觀的列印二叉樹
-
完成二叉樹的寬度優先遍歷(求一顆二叉樹的寬度)
遞迴序:
遞迴的核心程式碼:
def recur(Node):
if (Node == None):
return
#第一次到該節點的操作程式碼
recur(Node.left)
#第二次回到該節點所執行的程式碼
recur(Node.right)
#第三次回到該節點所執行的程式碼
要點 : 遞迴
遞迴序的基礎上,可以加工出先序、中序、後序。(順序是對於每個子樹都是這樣)
先序(頭,左,右): 列印頭節點,列印左節點,列印右節點(在遞迴演算法中第一次列印)
中序(左,頭,右):4,2,5,1,6,3,7(在遞迴演算法中第二次列印,第一次和第三次都不列印)
後序(左,右,頭):4, 5,2,6,7,3,1(在遞迴演算法中第三次列印,第一次和第二次都不列印)
非遞迴序
任何遞迴都可以改成非遞迴函式
自己準備一個棧
先序遍歷
後續遍歷
壓棧的時候先壓入左,後右,得到頭左右的順序,入棧出棧得到左右頭的後續遍歷
中序遍歷
思想
- 整顆樹左邊進棧
- 依次彈出的過程中,列印
- 對彈出節點的右節點依次操作
求二叉樹的寬度(完成二叉樹寬度的優先遍歷)
寬度優先遍歷
的基礎上操作
二叉樹的相關問題
- 搜尋二叉樹判斷:左樹的節點比根節點小,右樹的節點比根節點大
判斷:中序遍歷是升序,是搜尋二叉樹
- 完全二叉樹判斷:
- 滿二叉樹判斷
- 平衡二叉樹判斷:對任何一個子樹,左右樹的高度差不超過1
要左樹,要右數的遞迴套路
- 給定兩個二叉樹節點node1和node2, 找到他們的最低公共祖先節點
- 二叉樹的序列化和反序列化:記憶體裡的一棵樹變成字串形式/字串變成記憶體裡的二叉樹
- 如何判斷一個二叉樹是不是另一個二叉樹的子樹
9. 圖
1. 圖的儲存方式
- 鄰接表
點集作為單位:
- 鄰接矩陣(一定是個正方形)
2. graph
class Graph:
def __init__(self):
self.nodes = {}#點集 點序號:Node
self.edges = set()#邊集
class Edges:#邊
def __init__(self, weight, from_node, to_node):
self.weight = weight
self.from_node = from_node
self.to_node = to_node
class Node:
def __init__(self, value):
self.value = value
self.in_number = 0#入度
self.out_number = 0#出度
self.nexts = []#存連線的Node列表
self.edges = []#存發出的邊的列表
3. 寫介面
def transfer(matrix):
new_graph = Graph()#新建一個圖
for row in matrix:
from_node = row[0]
to_node = row[1]
weight = row[2]
#看from和to節點是不是已經存在與圖中
#新增節點到圖的nodes裡
if from_node not in new_graph.nodes.keys():
new_graph.nodes[from_node] = Node(from_node)
if to_node not in new_graph.nodes.keys():
new_graph.nodes[to_node] = Node(to_node)
#新增邊到edges裡
new_edge = Edge(weight, from_node, to_node)
new_graph.edges.add(new_edge)
#改變node中的其他值
new_graph.nodes[from_node].out_number += 1
new_graph.nodes[from_node].edges.append(new_edge)
new_graph.nodes[from_node].nexts.append(new_graph.nodes[to_node])
new_graph.nodes[to_node].in_number +=1
#驗證
'''
print('node %d in dict, value %d, in_number %d, out_number %d, nextsadd: %d, edgesweight: %d'\
%(from_node, new_graph.nodes[from_node].value, new_graph.nodes[from_node].in_number\
, new_graph.nodes[from_node].out_number, new_graph.nodes[from_node].nexts[-1].value,\
new_graph.nodes[from_node].edges[-1].weight))
'''
return new_graph
matrix = [[1,2,4],[2,3,3],[3,1,7],[3,2,3],[4,1,2]]
G1 = transfer(matrix)
4. 圖的寬度優先遍歷
非常重要: 在新增node.nexts時判斷是否註冊過
import queue
def bfs(node):
if node.value == None:
return
q = queue.Queue()#別忘了括號
register = set()#登錄檔,防止環狀
q.put(node)#進佇列
register.add(node)#註冊
while(not q.empty()):#佇列不空時
cur = q.get()
print(cur.value)#替換別的操作
for anode in cur.nexts:#每次進nexts時,新增的nexts都在佇列最後面,所以這一層走完才可以走下一層,即寬度優先
if anode not in register:#把沒有註冊的nodes裡面的node進佇列,並註冊
q.put(anode)
register.add(anode)
matrix = [['A','B',0],['A','C',0],['A','E',0],['B','C',0],['C','E',0],['B','D',0]\
,['B','A',0],['C','A',0],['E','A',0],['C','B',0],['E','C',0],['D','B',0]]
G2 = transfer(matrix)
bfs(G2.nodes['A'])
5. 圖的廣度優先遍歷
Important: 1. 每一層只入棧一個元素,需要break;2. 元素的處理位置在第一次入棧的時候,因為會出入棧好幾次。
def dfs(node):
if node.value == None:
return
stack = []
register = set()
stack.append(node)
register.add(node)
print(node.value)#important
while(stack):
cur = stack.pop()
#print(cur.value)
for anode in cur.nexts:
if anode not in register:
stack.append(cur)
stack.append(anode)
register.add(anode)
print(anode.value)#important
break#most important step,在這一層中只看一個node,然後cur也進棧
#記住處理元素的位置,node出棧次數超過一次,所以在第一次進棧的時候處理
6.拓撲排序
#拓撲排序(編譯器順序,先編譯入度為0的包,去除這個包和所帶來的影響,再找入度為0的包編譯)
#要求:單向圖,且有0入度的節點,沒有環
import queue
def sortedtopology(graph):
Inmap = {}#用來儲存node:in_number,來判斷要進入佇列的節點
zero_in_queue = queue.Queue()
for node_key, node in graph.nodes.items():#生成Inmap,同時找出此時入度為0的節點放入佇列
Inmap[node] = node.in_number
if node.in_number == 0:
zero_in_queue.put(node)
result = [] #要給出的列表
while(not zero_in_queue.empty()):#佇列不空時,取一個放入返回列表
cur = zero_in_queue.get()
result.append(cur)
for anode in cur.nexts:#抹除當前節點對剩餘序列的影響
Inmap[anode] -= 1
if Inmap[anode] == 0:
zero_in_queue.put(anode)
return result
matrix2 = [['d','b',0], ['e', 'b',0],['c','b',0],['e','a',0], ['c','a',0],['b','a',0]]
G2 = transfer(matrix2)
result = sortedtopology(G2)
for node in result:
print(node.value)
7. 最小生成樹演算法
1. 並查集
class Mysets:
def __init__(self, nodes):
self.mysets = {}# 字典 node:set
for node in nodes.keys():
self.mysets[nodes[node]] = {nodes[node]}#node類:node類的集合
#提供兩個函式,一個判斷是否連線,一個用來結合起來
def is_same_set(self, from_node, to_node):
from_set = self.mysets[from_node]
to_set = self.mysets[to_node]
return from_set == to_set#判斷是不是相同
def union(self, from_node, to_node):
from_set = self.mysets[from_node]
to_set = self.mysets[to_node]
for node in to_set:#把to_set裡的節點新增到fromset裡去,讓to_node的值和from_set相同
from_set.add(node)
#self.mysets[to_node] = from_set
self.mysets[node] = from_set ##most important :把to_set中的node的to_set都改為from_set
'''
測試資料
'''
matrix3 = [['a','b',3],['a','c',100],['a','d',7],['c','a',100],['d','a',7],['b','a',3],\
['c','b',5],['b','c',5],['c','d',100],['d','c',100],['b','d',2],['d','b',2]]
G3 = transfer(matrix3)
mysets = Mysets(G3.nodes)
'''
測試用例
'''
for i in myset.mysets:
for j in myset.mysets[i]:
print(j.value)
myset.union(G3.nodes['a'],G3.nodes['b'])
for node_set in myset.mysets:
print('---------')
for node in myset.mysets[node_set]:
print(node.value)
print('---------')
print(myset.is_same_loop(G3.nodes['a'], G3.nodes['c']))
2. K演算法(邊思想)
思想:
從最小邊開始判斷,新增並檢視是不是有環
- 對每個節點初始化一個set集合,只有自己在裡面
- 對所有的邊從小到大排序,從最小的邊開始遍歷
- 利用並查集判斷from節點和to節點的set是否相同
如果不同,把邊新增到results中,
from節點的set中新增toset中的所有資料
toset中的所有節點賦值為from節點所指向的set
def k_algorithm(graph):
results = []
mysets = Mysets(graph.nodes)
#判斷初始化是否成功
for node, node_set in mysets.mysets.items():
print('node:%s,set:'%(node.value), end = '')
for i in node_set:
print(' %s '%(i.value), end = ' ')
print('')
list_edges = list(graph.edges)
list_edges.sort(key = lambda x:x.weight)
for edge in list_edges:
print('-----------new loop------------------')
print('判斷邊edge: from %s, to %s, weight %d'%(edge.from_node, edge.to_node, edge.weight))
from_node = graph.nodes[edge.from_node]
to_node = graph.nodes[edge.to_node]
if not mysets.is_same_set(from_node, to_node):
results.append(edge)
mysets.union(from_node, to_node)
#判斷loop之後的是否成功
for node, node_set in mysets.mysets.items():
print('node:%s,set:'%(node.value), end = '')
for i in node_set:
print(' %s '%(i.value), end = ' ')
print('')
#判斷result是否正確
print('此時的results為:')
for edge in results:
print('edge: from %s, to %s, weight %d'%(edge.from_node, \
edge.to_node, edge.weight), end = ' ')
print('')
return results
#測試資料
lujing = k_algorithm(G3)
for i in lujing:
print('from %s, to %s, weight %d'%(i.from_node, i.to_node, i.weight))
3. P演算法(點思想)
1.隨機選擇一個點開始,註冊,在’邊‘的優先佇列中新增所有的邊進去,
2.當優先佇列不為空時,取出當前最小邊,判斷tonode沒有註冊,註冊,邊放入results,把tonode的所有邊放入佇列
import queue
def p_algorithm(graph):
node_register = set()
edge_priorityqueue = queue.PriorityQueue()
results = set()
for node_name in graph.nodes.keys():#解決森林問題,即有些圖不是連通圖。
node = graph.nodes[node_name]
node_register.add(node)
for edge in node.edges:
edge_priorityqueue.put((edge.weight, id(edge),edge))#當第一項相同時,第二項不相同,most important
#否則報錯edge和edge沒有實現比較方法
while(not edge_priorityqueue.empty()):
edge = edge_priorityqueue.get()[2]
#print(edge.weight)
to_node_name = edge.to_node
if graph.nodes[to_node_name] not in node_register:
node_register.add(graph.nodes[to_node_name])
results.add(edge)
for smalledge in graph.nodes[to_node_name].edges:
edge_priorityqueue.put((smalledge.weight,id(smalledge), smalledge))
break#沒有森林時使用
return results
results = p_algorithm(G3)
for i in results:
print(i.weight)
8. Dijkstra演算法
規定一個出發點,算出出發點到每一個節點的最短路徑
適用範圍:沒有權值為負數的邊