文章目录
最小生成树问题
最小生成树(Minimum Spanning Tree)
1.是一棵树
无回路
|V|个顶点一定有IV|-1条边
2.是生成树
包含全部顶点
|V|-1条边都在图里
3.边的权重和最小
性质:
向生成树中任加一条边都一定构成回路
最小生成树存在<一>图连通
贪心算法
1.什么是“贪”:每一步都要最好的
2.什么是“好”:权重最小的边
3.需要约束:
1).只能用图里有的边
2).只能正好用掉|V|-1条边
3).不能有回路
Prim算法一让一棵小树长大
void Prim()
{MST= (s);
while(1){
V=未收录顶点中dist最小者;
1f(这样的V不存在)
break;
将V收录进MST:dist[V]=0;
for(V的每个邻接点W)
if(dist[W]!=0)
if(E<v,w><dist[W]){
dist[W]=E<v,w>;
parent[W]=V;
}
}
if(MST中收的项点不到|V|个)
Ertor("生成树不存在”);
}
Kruskal算法一将森林合并成树
void Kruskal(Graph G)
{MST={};
while(MST中不到|V|-1条边&&E中还有边){
从E中取一条权重最小的边E<v,w>;/*最小堆*/
将E<v,w>从E中删除;
if(E<v,w>不在MST中构成回路)/*并查集*/
将E<v,w>加入MsT;
else
彻底无视E<v,w>;
}
if(MsT中不到|V|-1条边)
Error("生成树不存在”);
}
拓扑排序
1.AOE(Activity On Edge)网络
一般用于安排项目的工序
2.拓扑序:如果图中从V到W有一条有向路径,则V一定排在W之前。满足此条件的顶点序列称为一个拓扑序
3.获得一个拓扑序的讨程就是拓扑排序
4.AOV如果有合理的拓扑序,则必定是有向无环图(Directed Acyclic Graph,DAG)
void TopSort ()
{for( cnt= 0;cnt<|V|;cnt++)
V=未输出的入度为0的顶点:/*O(|V|)*/
iE(这样的v不存在){
Error("图中有回路”);
break;
}
输出V,或者记录V的输出序号;
for(V的每个邻接点W)
Indegree [W]--;
}
}
聪明的算法
随时将入度变为0的顶点放到一个容器里
void TopSort()
{for(图中每个顶点V)
if(Indegree[V]==0)
Enqueue(V,Q);
while (!IsEmpty (Q)){
V Dequeue(Q);
输出V,或者记录V的输出序号:cnt++;
for(V的每个邻接点W)
if (--Indegree[W]==0)
Enqueue(W,Q);
if(cnt!=|V|)
Error("图中有回路”);
}
简单排序
void x_Sort (ElementType A[],int N)
1.大多数情况下,为简单起见,讨论从小到大的整数排序
2.N是正整数
3.只讨论基于比较的排序(>=<有意义)
4.只讨论内部排序
5.稳定性:任意两个相等的数据,排序前后的相对位置不发生改变
6.没有一种排序是任何情况下都表现最好的
冒泡排序
void Bubble_Sort (ElementType A[],int N)
{for(P=N-1;P>=0:P--)
{flag =0;
for(i=0;i<P:i++)
{/*一趟冒泡*/
if(A[i]>A[i+1]){
Swap(A[i],A[i+1]);
flag=1;/*标识发生了交换*/
}
}
if(flag==0)break;/*全程无交换*/
}
}
插入排序
void Insertion_Sort(ElementType A[],int N)
{for(P=1;P<N;P++){
Tmp=A[P];/*摸下一张牌*/
for (i=P;i>0 &&A[i-1]>Tmp;i--)
A[i]=A[i-1];/*移出空位*/
A[i]=Tp;/*新牌落位*/
}
}
时间复杂度下界
对于下标i<j,如果A[i]>A[j],则称(i,j)是一对逆序对(inversion)
交换2个相邻元素正好消去1个逆序对
定理:任意N个不同元素组成的序列平均具有N(N-1)/4个逆序对。
定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为2(N2)。
这意味着:要提高算法效率,我们必须每次消去不止1个逆序对,每次交换相隔较远的2个元素
希尔排序
定义增量序列DM>DM-1>……>D1=1
对每个Dk进行“Dk-间隔”排序(k=M,M-1,……1)
注意:“Dk间隔”有序的序列,在执行“Dk-1-间隔”排序后,仍然是“Dk-间隔”有序的
void Shell sort (ElementType A[],int N){
for(D=N/2;D>0;D/=2){/*希尔增量序列*/
for(P=D;P<N;P++){/*插入排序*/
Tmp =A[P];
for (i=P;i>=D &&A[i-D]>Tmp;i-=D)
A[i]=A[i-D];
A[i]=Tmp;
}
}
}
原始希尔排序DM=LN/2」,Dk=LDk+1/2」
Hibbard增量序列
Dk=2k-1一相邻元素互质
Sedgewick增量序列
{1,5,19,41,109,……}即9×4i-9×2i+1或4i-3×2i+1
堆排序
选择排序
void Selection Sort (ElementType A[],int N)
{for(i=0:i<N:i++){
MinPosition ScanForMin(A,i,N-1 )/*从A[i]到A[N-1]中找最小元,并将其位置赋给MinPosition*/
Swap(A[i],A[MinPosition])
/*将未排序部分的最小元换到有序部分的最后位置*/
}
}
堆排序
void Heap Sort (ElementType A[],int N)
{for(i=N/2i>=0;i--)/*BuildHeap*/
PercDown(A,i,N )
for(i=N-1:i>0:i--){
Swap(&A[0],&A[i])/*DeleteMax */
PercDown(A,0,i)
}
}
归并排序
核心:有序子列的归并
/*L=左边起始位置,R=右边起始位置,RightEnd=右边终点位置*/
void Merge (ElementType A[],ElementType TmpA[],int L,int R,int RightEnd)
{LeftEnd=R-1:/*左边终点位置。假设左右两列挨着*/
Tmp=L;/*存放结果的数组的初始位置*/
NumElements =RightEnd -L+1;
while(L <=LeftEnd && R <=RightEnd ){
if(A[L]<=A[R])TmpA[Tmp++]=A[L++];
else
TmpA[Tmp++]=A[R++];
}
while(L<=LeftEnd)/*直接复制左边剩下的*/
TmpA[Tmp++]=A[L++];
while(R<=RightEnd)/*直接复制右边剩下的*/
TmpA[Tmp++]=A[R++];
for(i=0;i<NumElements;i++,RightEnd --)
A[RightEnd]=TmpA[RightEnd]
}
递归算法
void MSort {ElementType A[],ELementType TmpA[],
int L,int RightEnd)
{int Center;
if (L <RightEnd )
Center =(L+ RightEnd )/2;
MSort(A,TmpA,L,Center )
MSort(A,TmpA,Center+1,RightEnd )
Merge(A,TmpA,L,Center+l,RightEnd )
}
}
统一函数接口
void Merge_sort(ElementType A[],int N
{ElementType *TmpA;
TmpA=malloc(N*sizeof(ElementType));
if(TmPA!=NULL){
MSort(A,TmpA,0,N-1 );
free(TmpA);
}
else Error(w空间不足");
}
非递归算法
void Merge_pass(ElementType A[],ElementType TmpA[],int N,int1 ength)/* length=当前有序子列的长度*/
{for(i=0i<=N-2*length:i+=2*length)
Mergel(A,TmpA,i,i+length,i+2*length-1 )
if(i+length<N)/*归并最后2个子列*/
Mergel(A,TmpA,i,i+length,N-1);
else/*最后只剩1个子列*/
for (j=i;j<N;j++)TmpA[j]=A[j];
}
快速排序
void Quicksort(ElementType A[],int N)
{if(N<2)return:
pivot=从A[]中选一个主元;
将S={A[]\ pivot}分成2个独立子集;
A1=[a∈s | a≤pivot}和
A2=[a∈s | a≥pivot};
A[]=Quicksort (A1,N1)⊔
{pivot}⊔
Quicksort (A2,N2);
}
选主元
ElementType Median3(ElementType A[],int Left,int Right)
{int Center =Left + Right )/2;
if (A[Left ]>A[Center)
Swap(&A[Left],&A[Center]);
if (A[Left ]>A[Right])
Swap(&A[Left ],&A[Right );
if (A[Center ]>A[Right])
Swap(&A[Center ],&A[Right );
/*A[Left <=A[Center] <=A[Right] */
Swap(&A[Center],&A[Right-1]);/*将pivot减到右边*/
/*只需要考虑A[Left+1]…A[Right-2]*/
return A[Right-1];/*返回pivot*/
总代码
void Quick_Sort(ElementType A[],int N)
{
void Quicksort (ElementType A[],int Loft,int Right)
{if (Cutoff <=Right-Left ){
Pivot= Median3(A,Left,Right );
i =Left;j=Right- 1;
for(;;){
while A[++i <Pivot ){}
while A[--j ]>Pivot ){}
if (i <j)
Swap(&A[i],&A[j]);
else break;
}
Swap(&A[i],&A[Right-1] );
Quicksort(A,Left,i-1 );
Quicksort(A,i+1,Right );
}
else
Insertion_Sort(A+Left,Right-Left+1 )
}
}