13.将两个递增有序的单链表合并成降序的单链表,要求利用原来两个单链表的节点存放归并后的单链表
算法思想:将两个链表中的元素一一比较,使用头插法将结点插入结果表中
LinkList merge_List(LinkList L1,LiskLsit L2){
LinkList curA = L1->next;
LInkList curB = L2->next;
LinkList temp;//保存当前结点的下一个结点,以防断链
curA->next = NULL;//A作结果表
while(curA && curB){
if(curA->val > curB->val){
temp = curA->next;
cueA->next = A->next;
A->next = curA;
cueA = temp;
}else{
temp = curB->next;
curB->next = A->next;
A->next = curB;
cueB = temp;
}
}
if(curB){//防止代码冗余,待两段代码逻辑一养的代码
curA = curB;
}
while(curB){//如果A或B链表中还有元素
temp = curB->next;
curB->next = A->next;
A->next = curB;
curB = temp;
}
free(B);//释放B头节点
return A;//返回A链表
}
14.设A和B是两个单链表(带头结点),其中元素递增有序,设计一个算法从A和B中的公共元素产生单链表C,注意:要求不破坏A、B的节点
算法思想:遍历A,B链表寻找公共结点,创建新结点复制该公共结点将其尾插到创建的结果表中
LinkList Commom_NodeList(LinkList A,LinkList B){
LinkList curA = A->next;
LinkList curB = B->next;
//创建结果表
LinkList C = (LinkList)malloc(sizeof(ListNode));
C->next = NULL;
LinkList rC = C;//尾指针
while(curA && curB){
if(curA->val > curB->val){
curB = curB->next;
}else if(curA->val < curB->val){
curA = curA->next;
}else{
/创建新结点进行复制
LinkList s = (LinkList)malloc(sizeof(ListNode));
s->val = curA->val;
rC->next = s;
rC = s;
curA = curA->next;
curB = curB->next;
}
}
rC->next = NULL;
return C;
}
15.已知两个链表A和B分别表示两个集合,其元素递增排序,编制函数,求A和B的交集,并存放在A链表中,注意要释放其他节点
算法思想:以A作为结果表,将公共结点插入A中,并在遍历的过程中释放其他结点,再释放未遍历完的链表中的结点,最后释放B的头节点
LinkList Commom_List(LinkList A,LinkList B){
LinkList curA = A->next;
LinkList curB = B->next;
LinkList temp;
A->next = NULL;
LinkList rA = A;
while(curA && curB){
if(curA->val > curB->val){
temp = curB;
curB = curB->next;
free(temp);
}else if(curA->val < curB->val){
temp = curA;
curA = curA->next;
free(curA);
}else{
temp = curB;
rA->next = curA;
rA = curA;
curA = curA->next;
curB = curB->next;
free(temp);
}
}
if(curB){
curA = curB;
}
while(curA){ //释放没遍历完的链表中的剩余结点
temp = curA;
curA = curA->next;
free(temp);
}
rA->next = NULL;
free(B);//释放B的头节点
return A;
}
16.两个整数序列A=a1,a2,...,an和B=b1,b2,...,bn已经存入两个单链表中,设计一个算法,判断序列B是否是序列A的连续子序列
算法思想:朴素的模式匹配
匹配失败:B的长度超出要匹配的A的序列的长度,A先被遍历完
匹配成功:B先被遍历完或A,B同时被遍历完
bool subSet(LinkList A,LinkList B){
LinkList curA = A->next;
LinkList curB = B->next;
LinkList temp = curA;//保存当前A开始比较的结点
while(curA && curB){
if(curA->val == curB->val){
curA = curA->next;
curB = curB->netx;
}else{
temp = curA->next;//不相等时,从A的下一个结点开始比较
curA = temp;
curB = B->next; //B从头开始
}
}
if(curB == NULL){//若B被遍历完时
return true;
}else{
return false;
}
}
17.设计一个算法判断带头结点的循环双链表是否对称
算法思想:分别从双链表的头和尾同步相向遍历,直到两个指针相等(奇数个结点)或尾指针的next等于头指针时(偶数个结点)时,遍历过程中的结点值都相同,则对称,否则不对称
bool symmetry(DLinkList L){
LinkList front = L->next;
LinkList rear = L->prior;
while(front != rear || rear->next != front){
if(front->val == rear->val){
front = front->next;
rear = rear->prior;
}else{
return false;
}
}
return true;
}
18.有两个循环单链表,编写一个函数将链表h2连接链表h1之后,要求连接后的链表也是循环单链表
算法思想:遍历链表h1,找到h1的尾结点,将h2尾插到h1后,再遍历h2,找到h2的尾结点,将其链接到h1的头节点上
LinkList Link_List(LinkList h1,LinkList h2){
if(h1 == NULL){
return h2;
}else{
return h1;
}
LinkList head = h1;
while(h1->next){//找h1的尾结点
h1 = h1->next;
}
h1->next = h2;
while(h2->next){//找h2的尾结点
h2 = h2->next;
}
h2->next = head;
}
19.设有一个带头结点的循环单链表,其节点值为正整数,设计一个算法,反复找出单链表中节点值最小的节点并输出,然后将该节点从中删除,直到单链表为空为止,在删除表头节点
算法思想:解法和代码同第9题
void Del_minNode(LinkList L){
LinkList p,pre,temp;
while(L->next != L){//循环至只剩头结点
p = L->next;//初始时假设当前链表中第一个结点是最小的
pre = L;//pre始终指向最小结点的前驱结点
//找最小结点
while(p->next && pre->next->val > p->next->val){
pre = p;
p = p->next;
}
//输出并删除最小结点
print(pre->next->val);
temp = pre->next;
pre->next = pre->next->next;
free(temp);
}
free(L);//释放头节点
}
20.非循环双向链表L有头节点,有一个访问频度阈freq,初值为0,链表每进行一次Locate(L,x),值为x的节点的频度就加1,并且让节点保持按访问频度非增(递减)的顺序排列,同时最近访问的节点排在频度相同节点的前面,以便让频繁访问的节点靠近表头,试编写符合以上要求的Locate(L,x)运算的算法,返回找到节点的地址,类型为指针型元素值唯一
算法思想:查找该结点使其频度加1,并从当前位置删除该结点,按照频度大小查找该结点的插入位置并插入该结点,使其链表按频度递减
LinkList Locate(LinkList L,ElemType x){
LinkList cur = L->next;
LinkList pre;
while(cur){
if(cur->val == x){
cur->fraq++;//访问频度加1
pre = cur->prior;//保存其前驱结点,以便删除
//从当前位置删除
if(cur->next){//如果cur的下个结点不为空
cur->next->prior = pre;
}
pre->next = cur->next;
break;//跳出循环
}else{
cur = cur->next;
}
}
if(cur == NULL){//查找失败,链表中不存在x
return NULL;
}
//查找插入位置,pre指向其前驱结点
while(pre != L && pre->fraq <= cur->fraq){
pre = pre->prior;
}
//插入操作
cur->next = pre->next;
if(pre->next){
pre->next->prior = cur;
}
cur->prior = pre;
pre->next = cur;
return cur;
}
21.判断单链表是否有环
算法思想:Floyd判圈算法(龟兔赛跑算法)
快慢指针 :快指针一次走两步,慢指针一次走一步,如果链表中有环,快指针先进入环,慢指针进入环后,必在某一时刻,快慢指针相遇,如果无环,慢指针必将追不上快指针,而快指针先遍历结束
bool is_Circle(LinkList L){
LinkList slow = L;
Linklist fast = L;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
return true;
}
}
return false;
}
22.寻找链表倒数第k个结点
算法思想:定义两个指针,使第一个指针先遍历k次,之后两个指针再同步遍历,当第一个指针遍历到最后一个结点时,第二个指针指向倒数第k个结点。
int revese_k(LinkList list,int k){
if(!list || k == 0){
return 0;
}
LinkList cur = list->next;
LinkList pre = L->next;
while(k--){
cur = cur->next;
}
while(cur){
pre = pre->next;
cur = cur->next;
}
print(pre->val)
return 1;
}
23.找相交链表的第一个起始节点
算法思想:解法和代码同第8题
24.删除绝对值相等的节点,只保留靠近头结点的节点,结点的绝对值<=n
算法思想:申请一个数组空间,各结点的值作为数组下标,当初次访问某一结点的绝对值时,其数组元素设为1,代表已有该结点值,当访问到某一结点时,对应数组元素为1,即是绝对值相等的结点,删除该结点
void Delete_Node(LinkList head){
if(!head->next){
return;
}
//创建并初始化数组
int* arr = (int*)malloc(sizeof(int)*n+1);
for(int i = 0;i < n+1;i++){
arr[i] = 0;
}
LinkList cur = L->next,pre = L;//pre指向cur的前驱结点,以便删除
whiile(cur){
if(arr[abs(cur->val)] != 1){//初次访问该绝对值元素,保留该结点,并设置访问标记
arr[abs(cur->val)] = 1;
pre = cur;
cur = cur->next;
}else{//绝对值相等的结点,删除
pre->next = cur->next;
free(cur);
cur = pre->next;
}
}
free(arr);//释放数组
}
25.设线性表L={a1,a2,a3,...,an-2,an-1,an}采用带有头结点的单链表保存,设计一个空间复杂度为o(1)且时间尽可能高效的算法,重新排列L中的各结点,得到L'={a1,an,a2,an-1,a3,an-2,...}
算法思想:先用快慢指针找到中间结点,将第二条链表反转后,再将第二条链表逐个间隔插入第一条链表中
LinkList Revese_List(LinkList L){//反转链表
LinkList cur = L->next;
LinkList pre = L;
L->next = NULL;
LinkList temp;
while(cur){
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
//快慢指针找到中间结点(偶数个结点时中间结点为第二个结点)
LinkList midNode(LinkList L){
LinkList slow = L;
LinkList fast = L;
while(fast && fast->next){
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
void Set_List(LinkList L){
if(!L->next){
return;
}
LinkList SecondListStartNode = midNode(L->next);
LinkList SecondListHead = Revese_List(SecondListStartNode);
LinkList cur = SecondListHead;
LinkList pre = L->next;//指向插入位置的前驱结点
LinkList temp1;//保存cur的下一个结点,以防断链
LinkList temp2;//保存下一个插入位置的前驱结点
while(cur){
temp1 = cur->next;
temp2 = pre->next;
cur->next = pre->next;
pre->next = cur;
cur = temp1;
pre = temp2;
}
}