《算法IV——基础,数据结构,搜索,排序》读书笔记
——Jiang Bo
E-mail:jiang.bo.hit@gmail.com 2008.11.7
(一)连通算法
一问题描述:
假定给定一个含有M个整数对的序列L,其中每一对p-q表示p连接到q,且连通具有传递性,即p-q且q-r则p-r。问题:对于输入的p-q对,判断所有已经输入的整数对是否隐含p-q已连通,若否,输出该整数对。
二.合并-查找算法
1快速查找算法:
/**************************************************
* Connectivity.c *
* Copyright (c) Jiang Bo 2008.11 *
***************************************************/
#include <stdio.h>
#include <stdlib.h>
const int static N=1000;
int main()
{
int i;
int A[N];
int p,q;
for(i=0;i<N;i++)
{
A[i]=i;
}
while(scanf("%d %d",&p,&q))
{
int temp=A[p];
if(temp==A[q]) continue;
A[p]=A[q];
for(i=0;i<N;i++)
if(A[i]==temp)
A[i]=A[q];
printf("%d %d"n",p,q);
}
return 0;
}
分析:快速查找算法的基础是一个整数数组,当且仅当p与q连通时,p与q相等,数组元素A[i]初始为i。在合并p,q时要遍历整个数组,将所有值为p的数据项值改写为q的值。因此,该算法的执行效率至少是 M*N,其中M为整数对个数,N为数组大小。
2.快速合并算法:
/**************************************************
* Connectivity_union.c *
* Copyright (c) Jiang Bo 2008.11 *
***************************************************/
#include <stdio.h>
#include <stdlib.h>
const static int N=1000;
int main()
{
int A[N];
int i,j, p, q;
for(i=0;i<N;i++)
A[i]=i;
while(scanf("%d %d", &p,&q))
{
for(i=p;i!=A[i];i=A[i]);
for(j=q;j!=A[j];j=A[j]);
if(i==j) continue;
A[j]=i;
printf("%d %d"n",p,q);
}
return 0;
}
分析:快速合并算法中,数组的数据项值为同一连通集合内一个点的索引。若要判断两个点是否连通,只需要沿着索引查找,直至找到自己。当且进当得到同一对象时,p,q连通,否则修改索引为j的数据项值,使其指向i。可以证明该算法效率至少为M*N/2。
3.带权的快速合并算法:
/**************************************************
* Connectivity_union_v.c *
* Copyright (c) Jiang Bo 2008.11 *
***************************************************/
#include <stdio.h>
#include <stdlib.h>
const static int N=1000;
int main(void)
{
int i,j,p,q;
int A[N];
int sz[N];
for(i=0;i<N;i++)
{
A[i]=i;
sz[i]=1;
}
while(scanf("%d %d",&p,&q))
{
for(i=p;i!=A[i];i=A[i]);
for(j=q;j!=A[j];j=A[j]);
if(i==j) continue;
if(sz[j]>sz[i])
{
A[i]=j;
sz[i]+=sz[j];
}
else
{
A[j]=i;
sz[j]+=sz[i];
}
printf("%d %d"n",p,q);
}
return 0;
}
分析:在快速合并算法中,查找过程效率取决于该节点高度,因此采取适当方法降低树的高度,将有效的提高算法的执行效率,最简单的方法就是添加一个纪录每个节点的高度的数组,
该数组初始值为1,在合并时,始终保持将较小的树合并到较大的树上,同时修改相应的高度纪录。该算法的执行效率之多为M*lgN
TEST