(一)圖與網絡的基本概念
一、無向圖
含有的元素為頂點,弧和權重,但是沒有方向
二、有向圖
含有的元素為頂點,弧和權重,弧具有方向。
三、有限圖、無限圖
頂點和邊有限就是有限圖,否則就是無限圖。
四、簡單圖
既沒有環,也沒有兩條邊連接同一對頂點的圖
五、完全圖、二分圖
每一對不同的頂點都有一條邊相連的簡單圖稱為完全圖。
六、子圖
就是被包含的圖
七、頂點的度
就是頂點連接了幾條邊。
性質:1、全部頂點的度相加為偶數
2、 任意一個圖的奇頂點的個數為偶數。
(二)圖與網絡的數據結構
一、鄰接矩陣表示法
1、定義:
就是0-1矩陣,如果元素cij為“1”表示弧從第i個到第j個點,為“0”的話表示沒有。如果是無向圖則必定cij=cji。
2、一個demo:
3、缺點
浪費大量的空間
二、關聯矩陣表示法
1、定義
在關聯矩陣中,每行對應圖的一個節點,每列對應圖的一條弧。如果元素為“1”為一條弧的起點,元素為“-1”是一條弧的終點,元素為“0”與弧沒有關聯。
2、缺點:
浪費大量的弓箭
3、一個demo
三、弧表表示法
1、定義:
上面兩種方法都是以點優先,這種方法以邊優先,記錄下來每個邊的起點,終點和權重。
2、一個demo
四、鄰接表表示法
1、定義
就是用一個單向鏈表存儲所有的頂點,然后每個頂點又是一個單向鏈表的頭指針, 引導着每個由它出發的弧。
2、一個demo
五、星形表示法
1、前向星形表示法
(1)定義:
定義2個數組,一個數組記錄邊信息的數組,跟換標表示法類似,然后還有一個數組記錄每個出弧的起始地址編號
(2)demo
(3)性質
a、在point數組中,節點號比圖的頂點多一個,一定要有point(1)=1,point(n)=m+1,
(4)評價
能快速檢索每個節點的所有出弧,但是沒有辦法快速檢索每個節點的所有入弧。
2、后向星形表示法
(1)定義:
定義2個數組,一個數組記錄邊信息的數組,跟換標表示法類似,然后還有一個數組記錄每個出弧的起始地址編號,但是是記錄從終點到頂點。
(2)demo
3、雙星型表示法
(1)加前向星形表示法的基礎上,再加上一個正向弧對應的編號即可
(2)demo
(三)應用——最短路問題
一、從指定1點到其他所有點的最短路徑(無向圖)
1、算法
例子:
MATLAB編程求解
clc,clear; a=zeros(6); a(1,2)=50;a(1,4)=40;a(1,5)=25;a(1,6)=10; a(2,3)=15;a(2,4)=20;a(2,6)=25; a(3,4)=10;a(3,5)=20; a(4,5)=10;a(4,6)=25; a(5,6)=55; a=a+a'; ll=find(a==0); a(ll)=inf; pb(1:length(a))=0;pb(1)=1;index1=1;index2=ones(1,length(a)); d(1:length(a))=inf;d(1)=0;temp=1; %pb是用來標記是否走過(每次取最小路徑所到達的地點),index1是指遍歷地點的路徑,index2是指到底地點前一個地點,然后從index1
%中找到它的最短路徑。d是記錄從1到每個地點的最短路徑。 while sum(pb)<length(a) tb=find(pb==0); %取出沒走過的點 d(tb)=min(d(tb),d(temp)+a(temp,tb)); %用上一次的最小值,和前者與這次的步徑相加相比較,得出當前的最短路徑 tmpb=find(d(tb)==min(d(tb))); temp=tb(tmpb(1)); %取出目前最短的路徑,然后選定為下一個起點 pb(temp)=1; index1=[index1,temp]; temp2=find(d(index1)==d(temp)-a(temp,index1)); %確定到目前點之前一點,確定的方法是用到此點的最短路徑減去這次走的路徑與之前的最短路徑作比較。(按
%index1順序),這樣就可以得到上次來到此地的點。 index2(temp)=index1(temp2(1)); end d,index1,index2
二、兩個指定頂點之間的最短路徑(有向圖)
1、解法
約束條件的理解:i=1表示地點,當然不用回來了,出弧減入弧為1
i=n表示終點,當然不用出去了,出弧減入弧為-1
其他點有出有進,所以為0
2、demo
思路一:
以dp的思想來做,這樣的話,通過遞歸來做就可以
思路二:
直接遍歷,但是進行一個比較,明顯不是最優解的省去
(四)樹
一、基本概念
這里講解的樹為連通圖的生成樹。
二、應用——連線問題
解題思路:就是在連通賦權圖上求解出最小生成樹。
算法一:prim算法構造最小生成樹
1、思想:
先定義一個頂點的集合,定義一個邊的集合。然后構造一個最小生成樹。然后選一點,從這點出發,一直尋找權重最小的邊,加入到邊的集合,直到涵蓋了全部頂點為止。
2、demo
clc;clear; a=zeros(7); a(1,2)=50;a(1,3)=60; a(2,4)=65;a(2,5)=40; a(3,4)=52;a(3,7)=45; a(4,5)=50;a(4,6)=30;a(4,7)=42; a(5,6)=70; a=a+a'; a(find(a==0))=inf; result=[];p=1;tb=2:length(a); while length(result)~=length(a)-1 temp=a(p,tb); %取出p向量里儲存的頂點到其他未選中的點的邊 temp=temp(:); d=min(temp); %從中取出最小的,加入到result,將這個邊的終點加入向量p [jb,kb]=find(a(p,tb)==d); j=p(jb(1));k=tb(kb(1)); result=[result,[j;k;d]];p=[p,k];tb(find(tb==k))=[]; end result
算法二:Kruskal算法
1、思想
用index來存儲各邊端點的信息,當選中某一個邊的時候,就將這邊較的端點改為較小的端點,把后面的出現的也一並改掉,也就是所把這條邊刪掉。
2、demo
clc;clear; a(1,2)=50;a(1,3)=60; a(2,4)=65;a(2,5)=40; a(3,4)=52;a(3,7)=45; a(4,5)=50;a(4,6)=30;a(4,7)=42; a(5,6)=70; [i,j,b]=find(a); data=[i';j';b']; %data存儲每條邊的端點和權值,index記錄每條邊的端點 index=data(1:2,:); loop=max(size(a))-1; result=[]; while length(result)<loop temp=min(data(3,:)); flag=find(data(3,:)==temp); flag=flag(1); v1=data(1,flag);v2=data(2,flag); %每次找到之后,將數據存入data,而index就開始將線變成點,主要就是用來檢驗已經取過的樹有沒有已經走過這兩點,
%從而避免圈的出現。 if index(1,flag)~=index(2,flag) result=[result,data(:,flag)]; end index(find(index==v2))=v1; data(:,flag)=[]; index(:,flag)=[]; end result
(五)匹配問題
一、一些概念的理解= =
M其實就是邊兩端的點集
二、人員分配問題
1、提出
2、解決的算法
(1)匈牙利算法
(六)Euler圖和Hamilton圖
一、基本概念
1、Euler定義
Euler圖就是能夠不重復且走過每條邊能夠回到出發點的圖。
2、定理:
3、Hamilton定義
Hamilton圖就是能夠不重復且走過每個頂點能夠回到出發點的圖。
二、Euler回路的Fleury算法