一.集合求并集一般算法
1.思路分析:
有两个集合A和B,用线性表L1,L2表示,求他们的并集,一般我们都会想到的方法:用两个循环遍历两个线性表L1,L2中的元素,把L2中的元素与L1中的元素依次比较,如果L2中的元素不和L1中的元素相同,则把L2中这个元素存到L1的末尾,否则不存.
2.代码实现
//集合求并集,这里使用顺序表表示集合
void Union(SqList *L1,SqList *L2)
{
for(elemType* p=L2->elem;p<(L2->elem+L2->length);++p) //遍历L2中的所有元素
{
int rear=L1->length; //顺序表L1的末尾索引序号等于已存元素的数量
bool add=true; //是否添加的标记变量,初始为真
for(elemType* q=L1->elem;q<(L1->elem+L1->length);++q) //遍历L1中的所有元素
{
if(*p==*q) //如果L2中遍历到的元素与L1中的某个元素相同
add=false; //则添加标记为假
}
if(add) //如果添加标记为真
{
L1->elem[rear]=*p; //把L2中遍历到这个的元素添加到L1的末尾
++(L1->length); //L1的元素数量加1
}
}
}
这是非常普通的算法,且时间复杂度过高,以下有一种快速求集合的算法,但是只适用于有序集合.
二.有序集合求并集快速算法
1.思路分析:
有两个有序递增集合A和B,用线性表L1,L2表示,求他们的并集.我们先创建一个新的线性表L3,用来存储并集.初始我们用两个指针分别指向线性表L1,L2的头部,对他们的元素都只遍历1次,没错,只从头到尾遍历一次.在遍历的过程中,对两个指针所指向的元素进行比较,哪个指针指向的元素更小,就把这个元素存入L3中,然后指针下移.而另一个指针不能动.假如相等,就取其中一个元素存入L3中,两个指针同时下移.直到有一个线性表被遍历完,然后把另一个线性表剩下的元素依次存入L3中.
2.代码实现
//有序集合求并集(递增集合),这里使用顺序表表示集合
void MergeList(SqList *L1,SqList *L2,SqList *L3)
{
elemType *p=L1->elem; //指向L1的指针
elemType *q=L2->elem; //指向L2的指针
elemType *r=L3->elem; //指向L3的指针
for(L3->length=0;p<(L1->elem+L1->length)&&q<(L2->elem+L2->length);L3->length++)
{
if(*p==*q) //两指针所指元素相等情况
{
r[L3->length]=*(p++); //这里相等的情况我们都取L1的元素,且指针下移,当然也可以取L2中的元素,因为是一样的,没什么影响
q++; //指向L2的指针也下移
}
else //两指针所指元素不相等情况
r[L3->length]=(*p)<(*q)?*(p++):*(q++); //取两指针指向的更大的那个元素,并且那个指针下移
}
while(p<(L1->elem+L1->length)) //如果是L1中的元素有剩余没有被遍历到
{
r[L3->length++]=*(p++); //剩余元素通过循环依次加入到L3的末尾
}
while(q<(L2->elem+L2->length)) //如果是L2中的元素有剩余没有被遍历到
{
r[L3->length++]=*(q++); //剩余元素通过循环依次加入到L3的末尾
}
} //注意:上面两个while语句只有其中一个会被执行
这里可能有人又有疑问了,要是我的集合是递减的怎么办?那原理还是不变,我们就把比较两指针指向的更小元素存入线性表L3改成更大元素存入线性表L3就行了.
三.总结
一般算法虽然效率低但是不管集合是否有序,都能使用,快速算法虽然效率高,但是只能适用于有序集合,所以我们要根据情况来选择算法.