学习完了数据结构链表的部分,也看完了视频。
今天做下链表的课后题
题目:已知有两个带头节点的的单链表A和B,A和B中的元素中的元素按从小到大排列,设计一个算法,求A和B的交集C,将A和B中相同的元素插入到C中。
开始的错我在于我编写的MergeList函数的问题,错在对指针操作有误
void MergeList(LinkList A,LinkList B,LinkList *C)
{
int i=1;
ListNode *pa,*pb,*pc;
pa=A->next;
pb=B->next;
*C=A;(*C)->next=NULL;
pc=*C;
while(pa&&pb)
{
if(pa->data == pb->data)
{
pc->next=pa;
pc=pa;
pa=pa->next;
pb=pb->next;
}
else
if(pa->data < pb->data)
pa=pa->next;
else
pb=pb->next;
}
}
也发现出错误在于指针pa与pc转换时
void MergeList(LinkList A,LinkList B,LinkList *C)
{
int i=1;
ListNode *pa,*pb,*pc;
pa=A->next;
pb=B->next;
InitList(C);
pc=*C;
while(pa&&pb)
{
if(pa->data == pb->data)
{
InsertList(pc,i,pa->data);
i++;
pa=pa->next;
pb=pb->next;
}
else
if(pa->data < pb->data)
pa=pa->next;
else
pb=pb->next;
}
}
运行结果正确
关于求交集的算法,首先能想到的算法就是遍历法,对于排序好的是时间复杂度是O(N);
其次就是集合压缩,(该算法是参考)
对于一个集合来说,我们很容易就可以得到集合的最大值和最小值,假设集合A的最大值和最小值分别为MaxInA,MinInA;假设集合B的最大值和最小值分别为MaxInB,MinInB;那么集合A的所有元素一定在闭区间【MinInA, MaxInA】里面,集合B的所有元素一定在闭区间【MinInB, MaxInB】里面,从这两个集合里面我们可以作如下判断:(集合A和集合B都在链表中!此算法使用链表结构,操作起来比数组更方便)
1. 若MinInA == MinInB或者MaxInA == MaxInB,那么MinInA 或者MaxInA (相等的那个数)就一定在交集里面,存入交集(可以用数组存),删除链表中相应的结点;若不想等则跳到第3步;
2. 重新找到集合A和B中的最大值和最小值MinInA 、MaxInA 、MinInB、MaxInB;跳回第1步;
3. 更新区间(交集的区间),区间的更新如下:区间下界为Lower = max(MinInA, MinInB),上届为Upper = min(MaxInA , MaxInB),那么剩下的交集一定在闭区间【Lower ,Upper】里面,按照这个区间来剔除掉集合A和集合B中不符合条件的元素,剔除结束后,若其中一个集合为空,跳到第4步,否则返回第2步;
4. 程序结束,退出!
这种适用于集合里面数值比较散乱,最大值最小值差值比较大的情况!算法的思想在于不断减小搜索的范围,时间的消耗主要在查找集合的最大值和最小值上,我们来看一个例子,集合A= {1, 3, 10, 100, 123, 0, 6} ,B = {3, 2, 10, 23, -1},
集合A的闭区间【0, 123】,集合B的区间【-1,23】,交集的闭区间就为【0,23】,按照这个区间,剔除集合A中的{ 100, 123},剔除集合B的{-1},集合A={1, 3, 10, 0, 6}集合B={3, 2, 10, 23},没有相等的,继续缩小范围,为【2,10】,这时MaxInA == MaxInB,满足条件,把10存入交集数组中,剔除两个集合的结点;集合变为A= {3,6}集合B={3},满足MinInA == MinInB或者MaxInA == MaxInB,把3存入交集数组中,集合B为空,结束!如图: