Q2Q1:递归删除不带头节点的单链表中所有为x的值
Ans:
void Function(int x,SingleList &L){
SingleList p = L;
if(p->next = null||L==null) return;
if(p->data == x){
p->next = p->next->next;
}
Function(x,p->next);
}
Q2:带头节点的单链表删除所有值为x的节点并释放内存
Ans:
void Function(int x,Singlelist &L){
SingleList p = L,q;
while(p!= NULL){
if(p->next->data == x){
q = p->next;
p->next = p->next->next;
free(q);
}
}
}
Q3:反向输出链表数据
Ans:遍历链表,将数据取出存入数组,数组反向输出
Q4:删除最小节点
Ans:联想删除数组最小值,遍历数组使用min记录最小值下标,一轮遍历结束后再删除最小值。这里使用minp指向最小值的前驱,一轮遍历结束用minp->next = minp->next->next
Q5:单链表原地逆转
Ans:联想顺序表的原地逆转,用一个swap(a,b)完成元素关于中心点交换顺序。这里使用swap函数完成节点关于中心点交换位置。由于限制空间,我们可以牺牲时间来换取空间。
Q6:乱序单链表升序
Ans:用辅助数组取出单链表的数据,排序后再顺序放入单链表内。
Q7:乱序单链表删除所有介于a,b的值。
Ans:循环遍历链表,符合条件删除即可。
Q8:找出两个链表的公共节点。
Ans:如果找寻多个公共节点的话,我觉得得改编一下LCD算法,如果仅仅找一个公共节点的话双重for循环寻找就行。
Q9:乱序单链表升序输出。
Ans:双重循环,内循环寻找最大值输出并删除最大节点然后释放最大节点的内存,外循环控制内循环次数。
Q10:单链表拆分成两个单链表。
Ans:太简单,不说了。
Q11:单链表就地拆分成两个单链表。
Ans:就地拆分要求辅助空间为O(1),a1,b1,a2,b2,a3,b3观察一下发现b1和a3交换可以实现a全部在左边,b全部在右边,变成a1,a3,a2,b2,b1,b3。然后a3,a2交换,b2,b1交换就可以实现a1,a2,a3,b1,b,2,b3然后拆分得到A,B。这题需要先将a交换到左边,b交换到右边,拆分后各自交换内部顺序就可以了。内部交换顺序不能使用递归函数!递归调用系统栈,造成额外的辅助空间!导致辅助空间超过O(1)。
Q12:删除单链表中重复的值。
Ans:没说不能使用set,借用顺序表中去除重复值的方法,将数据取出放入set,使用迭代器遍历放入链表,然后截断链表,释放后面多余节点的内存。
Q13:将两个升序链表归并为一个降序链表
Ans:使用双重循环将两个升序链表归并为一个升序链表,然后对升序链表做对称变化。
Q15:抽取升序A,B链表公共节点放入A中
Ans:如果没有升序这个条件我觉得需要用到LCD算法,但是说了升序,那就简单多了。
a的指针后移在未找到第一个不小于b指针所指元素前都删除节点,否则如果数值相等将b指针所指节点插入a指针,a,b同时后移一位,如果b>a,则b指针后移一位。这种算法借助了求最长递增子序列的思想,时间复杂度是O(nlog n),比两个链表双重循环从头到尾O(n^2)判断快。
SingleList function(SingleList &a,SingleList b){
SingleList p = a,q = b;
while(p != NULL && b != NULL){
//寻找第一个不小于q->next->data的节点
//小于直接删除该节点
while(p->next->data < b->next->data){
p->next = p->next->next;
p = p->next;
}
//找到等于的节点将该节点连接上a
if(q->next->data = b->next->data;){
//把b赋给q
q = b;
//q尾插于p
q->next = p->next;
p->next = q;
//p后移一位
p = p->next;
}
//b后移一位
b = b->next;
}
return a;
}
Q14:在15的基础上不破坏表a,b
Ans:直接用数组取出a,b的元素,求最长公共子序列就行了。
Q16:判断b是否为a的连续子序列
Ans:没想到好方法,暴力枚举吧,b中只要有一个元素不和a相同就退出一次外循环。时间复杂度为O(n^2)
Q17:判断带头节点的循环双链表是否对称
Ans:循环双链表是有prior指针的,可以向前搜索也可以向后搜索。所以直接搜索,如果向前和向后同步搜索遇到一个不相同的就不是对称的。如果前行指针p和后行指针q同时指向一个节点或者p->next = q && q->prior = p,搜索结束。
Q18:将两个循环单链表合并为一个循环单链表。
Ans:a表找到表尾,连上b表的头节点,b表找到表尾,连上a表头节点。没什么难度。
Q19:将最小的节点删除直到表空,最后删除头节点。
Ans:这个让我想起了约瑟夫环问题,其实是一样的。包含两个函数地一个是找最小值的前驱,第二个是删除最小值节点。外面套一个循环,最后删除头节点。
Q20:根据访问频度排序,相同频度最近一次访问排在最前。
Ans:让我想起了操作系统的任务调度。索性我不考操作系统,不然又得头疼。1.题目没有说明节点地址是否可以修改,2.没有说明x是否重复。故我设想节点地址可修改,x地址可修改,使用pair<>数组将每个节点的数据和频度取出,将x的频度+1后按照频度进行排序,然后放回链表内。
Q21:输出倒数第K个节点对应的data。
Ans:判断K是否会超过链表长度,如果超过直接返回0,没有超过则将头指针后移并length-k+1位,返回1。
int GetLength(SingleList L){
int length = 0;
while(L->link != NULL) length ++;
return length;
}
int Find_K(SingleList head){
int length = GetLength(head);
//链表长度不长于K或空表返回0
if(length <= K) return 0;
//head后移length-K+1位找到倒数第K个节点
for(int i = 0 ; i < length-K+1 ; i ++)
head = head->link;
printf("%d",head->data);
return 1;
}
Q22:找到相同后缀。
Ans:我能想到的最快的办法是以空间换时间,将两个链表的数据分别取出存入数组a,b,a的长度位lenA,b的长度位lenB,a,b逆序寻找第一个不相同的字母位置k,k即为所求位置。然后链表A头指针后移lenA-k+1,链表B头指针后移lenB-k+1,就是链表对应相同后缀的开始节点位置。这种做法写法也比较简单,代码不写了。四个平行单重循环,故时间复杂度位O(n)。
Q23:单链表绝对值去重。
Ans:这类题目貌似在各种抽象数据类型里面都比较吃香,我一直建议使用set容器去重,然后放回链表中。
题目要求给出数据类型定义,下面给出抽象数据类型。
class Singlelist{
private:
int data;
SingleList *next;
public:
Singlelist Insert();
Singlelist Pop();
Singlelist Size();
Singlelist GetFront();
Singlelist GetByValue();
Singlelist Remove(SingleList L);
};