链表p38 1-20

目录

1.递归删除不带头结点的单链表中所有值为x的结点

2.删除带头结点单链表中所有值为x的节点并释放节点空间,假设x不唯一

3.把带头结点的单链表从尾到头反向输出(过)

方法1.先逆置再输出

方法2.递归(栈的思想)

4.删除带头结点的单链表中最小值的结点

5.带头结点单链表就地逆置

6.对带头结点的单链表排序(递增)

7.在带头结点的无序单链表中删除所有介于给定值之间的元素

8.找出两个单链表的公共结点

9.递增输出一个单链表的所有节点的数据元素并释放节点存储空间

10.分解带头结点的单链表,A表含有序号为奇数的元素,B表含有序号为偶数的元素

11.就地拆分(奇偶拆分)一个带头结点单链表,使A为正序,B为逆序

12.在递增有序的单链表中删除数值相同的节点-过

13.将两个递增排列的单链表,归并为一个递减排列的单链表(要求利用原来两个单链表的结点存放归并后的单链表)-过

14.两个带头结点递增有序的单链表,把两个单链表中的公共元素产生新链表,要求不破坏原来的链表

15.求两个递增排列的单链表的交集

16.判断两个单链表中的数值,B中元素是否是A中元素的连续子序列

17.判断带头结点的循环双链表是否对称

18.两个循环单链表,把后者链接在前者之后,要求链接后的链表仍是循环链表

19.结点均为正整数的带头结点单链表,反复找出最小节点并输出,然后删除,直到链表为空,在删除表头结点

20.头指针为L的带表头结点非循环双链表,结点除了前驱pred后继next数据data还包括一个访问频度freq。在链表启用前,全部初始化为0.。每当在链表中进行一次Locate(L,x)运算时,令元素值为x的f、频度域值+1,并使此链表以访问频度排序,且相同频度结点时最近访问的结点排在前面,以便使频繁访问的结点总是靠近表头。请编写符合要求的Locate函数,以指针型返回找到结点的地址


1.递归删除不带头结点的单链表中所有值为x的结点

  1. 终止条件:若表空,不做任何事
  2. 递归主体:值相等,删除结点,继续处理后续结点。值不等,递归处理子序列 
  3. 引用型,是直接对原链表操作,所以不会造成断链
void Delete_x(Linklist &l,int x){
	if(l==NULL) return;   //空表情况 

	if(l->data!=x){                 //不等的情况 
		Dlete_x(l->next,x);
		return;
	}      
                                     
	LNode *p;                    //与x相等的情况 
	p=l;
	l=l->next;
	free(p);
	Delete_x(l,x);
} 

2.删除带头结点单链表中所有值为x的节点并释放节点空间,假设x不唯一

p做判断指针,指向待判断结点的前驱,若p的后继的值=x就删除,若不等于就判断下一个 

void Delete_x(Linklist &l,int x){
   if(l->next==NULL) return;    //表空情况 
   Lnode *p=l;
   
   while(p->next){                  //遍历链表 
	  if(p->next->data!=x)  p=p->next;          //值不等情况直接下一个 
	  else {                             //值相等情况做链表结点删除操作 
	  	Lnode *temp=p->next;
	  	p->next=p->next->next;
	  	free(temp);
	  }
   }
} 

3.把带头结点的单链表从尾到头反向输出(过)

方法1.先逆置再输出

void reverse(Linklist &l){
	if(l||l->next) return;
	
	Linklist *p=l->next,*temp;
	l->next=NULL;
	while(p->next){
		*temp=p->next;
		p->next=l->next;
		l->next=p; 		
		p=temp;		
	}
	while(l->next){
		printf("%d",l->next->data);
		l=l->next;
	}printf("%d",l->data);
} 

方法2.递归(栈的思想)

每当访问一个节点时,先递归输出该节点自身,这样链表就反向输出了。

void R_print(Linklist l){
	if(l->next) R_printf(l->next);
	printf("%d",l->data); 
}

4.删除带头结点的单链表中最小值的结点

用p扫描单链表,pre指向p所指结点的前驱,用minp保存值最小的结点指针(初值为p),minpre指向minp所指结点的前驱(初值为pre)。一边扫描一边比较,若p->data小于minp->data,则将p、pre分别赋给minp、minpre。当p扫描完毕,minp指向最小值结点,minpre指向最小值结点的前驱节点,再将minp所指结点删除即可。

void delete_min(Linklist &l){
	Lnode *pre=l,*p=pre->next;
	Lnode *minpre=pre,*minp=p;
	while(p!=NULL){
		if(p->data<min->data){
			minp=p;
			minpre=pre;
		}
		pre=p;
		p=p->next; 
	}
	minpre->next=minp->next;
	free(minp);	 
}

5.带头结点单链表就地逆置

6.对带头结点的单链表排序(递增)

类似插入排序算法的思想,先构成只含有一个数据节点的有序单链表,然后依次扫描单链表中剩下的结点*p(直至p==NULL),在有序表中通过比较查找插入*p的前驱节点:*pre,然后将*p插入*pre之后

void sort_list(Linklist &l){
	Lnode *pre,*p=l->next;
	Lnode *r=p->next;  //存上位置否则就丢了 
	p->next=NULL;//此时l表中只有原链表中的第一个结点
	p=r; 
	
	while(p!=NULL){
		r=p->next;//存位置
		pre=l;
		while(pre->next!=NULL&&pre->next->data<p->data)
			pre=pre->next;
		p->next=pre->next;
		pre->next=p;
		p=r;		 
	}	 
}

7.在带头结点的无序单链表中删除所有介于给定值之间的元素

逐个节点检查,执行删除

void rangeDelete(Linklist &l,int min,int max){
	Lnode *pre=l,*p=l->next;
	while(p!=NULL){
		if(p->data>min&&p->data<max){
			pre->next=p->next;
			free(p);
			p=pre->next;
		}
		pre=p;
		p=p->next;
	}	 
}

8.找出两个单链表的公共结点

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode *pa=headA,*pb=headB;
    while(pa!=pb){
        pa=pa==NULL?headB:pa->next;
        pb=pb==NULL?headA:pb->next;
    }
    return pa;
}

9.递增输出一个单链表的所有节点的数据元素并释放节点存储空间

对链表进行遍历,在每次遍历中找出整个链表的最小值元素,输出并释放结点所占空间:再查找次小值元素,输出并释放空间。如此直至链表空,最后释放头结点。

void Min_delete(Linklist &l){
	Linklist *minpre,*p,*temp;
	while(l->next!=NULL){
		minpre=l;
		p=l->next;
		while(p->next!=NULL){  //找到最小值的前驱 
			if(p->next->data<minpre->next->data)
				minpre=p;
			p=p->next;	
		}
		printf("%d",minpre->next->data);  //打印最小值 
		temp=minpre->next;       //删除最小值 
		minpre->next=minpre->next->next;
		free(temp);              //释放结点空间 
	}
	free(l);        //释放头结点 
}

10.分解带头结点的单链表,A表含有序号为奇数的元素,B表含有序号为偶数的元素

设置一个访问序号变量初值为0,每访问一个节点就序号+1,然后根据序号的奇偶性将节点插入到AB表中,重复操作直到表尾。

Linklist disCreat(Linklist &A){
	int i=0;
	Linklist B=(Linklist)malloc(sizeof(LNode));
	B->next=NULL;
	Lnode *ra=A,*rb=B;
	Lnode *p=A->next;
	A->next=NULL;
	
	while(p!=NULL){
		i++;
		if(i%2==0){
			rb->next=p;   //尾插 
			rb=p;
		}	
		else{
			ra->next=p;
			ra=p;
		}
		p=p->next;
	}
	ra->next=NULL;
	rb->next=NULL;
	return B;
}

11.就地拆分(奇偶拆分)一个带头结点单链表,使A为正序,B为逆序

采用上题的思路,但不设序号变量。二者的差别仅在于对B表的建立不采用尾插法而是头插法。

Linklist discreat_2(Linklist &A){
	Linklist B=(Linklist)malloc(sizeof(Lnode));
	B->next=NULL;
	Lnode *p=A->next,*temp;
	Lnode *ra=A;
	
	while(p!=NULL) {
		ra->next=p; 
		ra=p;
		p->next=p;
		temp=p->next;   
		p->next=B->next;
		B->next=p;
		p=temp;    
	}
    ra->next=NULL;
    return B;
}

12.在递增有序的单链表中删除数值相同的节点-过

由于是有序表,所有相同值域的节点都是相邻的。用p扫描递增链表l,若*p节点的值域等于其后继节点的值域,则删除后者,否则p移向下一个节点

void Delete(Linklist &l){    	
	if(l==NULL) return;
	Linknode *p=l; //无头结点 
	
	while(p!=NULL){
		if(p->data==p->next->data) p->next=p->next->next;
		else p=p->next;
	}
} 

13.将两个递增排列的单链表,归并为一个递减排列的单链表(要求利用原来两个单链表的结点存放归并后的单链表)-过

两个链表已经递增次序排列,合并时,均从第一个节点进行比较,较小的头插法链入表中,同时后移工作指针。若有剩余则依次头插法链入新链表中

void merge(Linklist &A,Linklist &B){ 
	Lnode *pa=A->next,*pb=B->next,*temp;
	A->next=NULL;
	B->next=NULL;
	
	while(pa!=NULL&&pb!=NULL){
		if(pa->data<=pb->data) {
			temp=pa->next;
			pa->next=A->next;
			A->next=pa;
			pa=temp;		
		} else{
			temp=pb->next;
			pb->next=B->next;
			B->next=pb;
			pb=temp;
		}
	}
	if(pa!=NULL){
		temp=pa->next;
		pa->next=A->next;
		A->next=pa;
		pa=temp;
	} else if(pb!=NULL){
		temp=pb->next;
		pb->next=B->next;
		B->next=pb;
		pb=temp;
	}
	free(B)  ;
} 

14.两个带头结点递增有序的单链表,把两个单链表中的公共元素产生新链表,要求不破坏原来的链表

表A、B都有序,可从第一个元素起依次比较A、B两表的元素,若元素值不等,则值小的指针往后移,若元素值相等,则创建一个值等于两节点的元素值的新节点,使用尾插法插入到新链表中,并将两个原表指针后移一位,直到其中一个链表遍历到表尾

void Get_common(Linklist A,Linklist B){ 
	 Lnode *p=A->next,*q=B->next,*r,*s;
	 Linklist C=(Linklist)malloc(sizeof(Lnode));
	 r=C;
	 
	 while(p!=NULL&&q!=NULL){
	 	if(p->data<q->data) p=p->next;
	 	else if(p->data>q->data) q=q->next;
	 	else{
	 		s=(Lnode*)malloc(sizeof(Lnode));
	 		s->data=p->data;        //尾插 
	 		r->next=s;
	 		r=s;
	 		p=p->next;
	 		q=q->next;
		 }
	 }
	 r->next=NULL;
} 

15.求两个递增排列的单链表的交集

采用归并的思想,设置两个工作指针pa pb对两个链表进行归并扫描,只有同时出现在两集合中的元素才链接到结果表中且仅保留一个,其他节点全部释放。当一个链表遍历完毕后,释放另一个表中的剩下所有节点

Linklist Union(Linklist &A,Linklist &B){ 
	Lnode *pa=A->next,*pb=B->next,*temp;
	pc=A;
	
	while(pa!=NULL&&pb!=NULL){
		 if(pa->data<pb->data){
		 	temp=pa;
		 	pa=pa->next;
		 	free(temp);
		 }
		 else if(pa->data>pb->data){
		 	temp=pb;
		 	pb=pb->next;
		 	free(temp);
		 }
		 else{
		 	pc->next=pa;
		 	pc=pa;
		 	pa=pa->next;
		 	temp=pb;
		 	pb=pb->next;
		 	free(temp);
		 }
	}
	pc->next=NULL;
	free(B);
	return A;
} 

16.判断两个单链表中的数值,B中元素是否是A中元素的连续子序列

因为两个整数序列已经存入两个链表中,操作从两个链表的第一个结点开始,若对应数据相等,则后移指针;若数据不等,则A链表从上次开始比较结点的后继开始,B链表仍从第一个结点开始比较,直到B链表到尾表示匹配成功。A链表到尾而B链表未到尾表示失败。操作中应记住A链表每次的开始结点,以便下次匹配时好从其后继开始

int Pattern(Linklist A,Linklist B){ 
	Lnode *pa=A,*pb=B,*pre=A;
	while(pa!=NULL&&pb!=NULL){
		if(pa->data==pb->data){   //结点值相同,继续检查 
			pa=pa->next;
			pb=pb->next;
		}
		else{     //结点值不同,让pa回到pre->next,让pb回到头上重新比较 
			pre=pre->next;
			pa=pre;
			pb=B;
		}
	if(pb==NULL) return 1;
	else return 0;
	}
} 

17.判断带头结点的循环双链表是否对称

让p从左向右扫描,q从右向左扫描,直到它们指向同一节点或者结点相邻为止,若它们所指结点值相同,则继续比较,否则返回0,若全部相等,返回1.

int Symmetry(DLinklist L){
	Dndoe *p=L->next,*q=L->prior;
	while(p!=q&&p->next!=q)
		if(p->data==q->data){
			p=p->next;
			q=q->prior;
		}
		else return 0;
	return 1;
} 

18.两个循环单链表,把后者链接在前者之后,要求链接后的链表仍是循环链表

找到两个链表的尾指针,将第一个链表的尾指针与第二个链表的头结点链接起来,再使之成为循环的

Linklist Link(Linklist &h1,Linklist &h2){
	Lnode *p=h1,*q=h2;
	while(p->next!=NULL)	p=p->next;
	while(q->next!=NULL)	q=q->next;
	p->next=h2;
	q->next=h1;
	return h1;
}

19.结点均为正整数的带头结点单链表,反复找出最小节点并输出,然后删除,直到链表为空,在删除表头结点

表不空时用一个循环遍历单链表,每循环一次查找一个最小值结点(minp保存最小值结点,minpre指向最小值节点前一个节点),输出最小值节点,然后删除,最后释放头结点。

void Delete_min(Linklist &L){
	Lnode *minp,*minpre,*p,*pre;
	while(L->next!=L){
		p=L->next;
		pre=L;
		minp=p;
		minpre=pre;
		while(p!=L){
			if(p->data<minp->data){
				minp=p;
				minpre=pre;
			}
			pre=p;
			p=p->next;
		}
		printf("%d",minp->data);
		minpre->next=minpre->next->next;
		free(minp);
	}
	free(L);
}

20.头指针为L的带表头结点非循环双链表,结点除了前驱pred后继next数据data还包括一个访问频度freq。在链表启用前,全部初始化为0.。每当在链表中进行一次Locate(L,x)运算时,令元素值为x的f、频度域值+1,并使此链表以访问频度排序,且相同频度结点时最近访问的结点排在前面,以便使频繁访问的结点总是靠近表头。请编写符合要求的Locate函数,以指针型返回找到结点的地址

主要考察双链表的查找、删除和插入。

首先在双向链表中查找数据值为x的结点,查到后,将节点从链表上摘下,然后在顺在结点的前驱查找该节点的插入位置(频度递减,且排在同频度第一个,即向前找到第一个比它的频度大的结点,插入位置为该节点之后)并插入到该位置

DLinklist Locate(DLinklist &L,int x){
	Dnode *p=L->next,*pre;
	while(p&&p->data!=x) p=p->next;
	if(!p){
		printf("不存在值为x的结点\n");
		exit(0);
	}
	else{
		p->freq++;
		pre=p->pred;
		p->next->pred=p->pred;
		p->pred->next=p->next;
		while(pre!=L&&pre->freq<=p->freq) pre=pre->pred;
		p->next=pre->next;
		pre->next->pred=p;
		p->pred=pre;
		pre->next=p;
	}
	return p;
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值