单链表题锦集

##1.删除不带头节点的单链表L中所有值为x的结点
思路1:递归算法

void Delete_X(Linklist &L,ElemType x){
	LNode *p;
	if(!L) return NULL;
	if(L->data==x){
		p=L;       //删除 L,并让 l 指向下一个节点 
		L=L->next;
		delete p;
		Delete(L,x);
	}else
	    Delete(L->next,x);
}

评价 :此算法需要一个工作栈,深度O(n),时间复杂度o(n)。上述代码直接delete p不会断链,L为引用,直接对原链表操作,不会断链。
思路2:常规遍历

void Delete_X(Linklist &L,ElemType x){
	LNode *pre=L,*p;   //  p是检测指针,pre是p的前驱
	while(!p)
		if(p->data==x){ //寻找被删结点
	     	pre->next=p->next;
	     	delete p;      
		    p=p->next;
		}else{
		pre=p;
	    p=p->next;
    }
}

##2.带头结点链表排序(假设升序)
思路:采用直接插入排序算法思想,先构造成只含一个数据结点的有序单链表,然后依次扫描单链表中剩余结点 *p (直至p==NULL),在在有序表中通过比较查找 *p 的前驱结点 *pre ,然后将 *p 插入到 *pre之后。

void *Sort(Linklist &L){
	LNode *p=L->next,*pre;
	LNode *r=p->next;//r保持 *p 的后继指针,以保证不断链 
	p->next=NULL;//构造只含一个数据节点的有序表 
	p=r;
	while(!p){
		r=p->next; //保存 *p 的 后继结点指针 
		pre=L;
		while(pre->next!=NULL && pre->next->data<p->data)
		    pre=pre->next;  //在有序表中查找 *p 的前驱结点 *pre 
		p->next=pre->next; //将*p 插入到 *pre之后 
		pre->next=p;
		p=r;           // 扫描原单链表中剩下的结点 
	}
} 

评价:时间复杂度o(n^2),为提升时间性能,可先将链表数据复制到数组中,然后采用时间复杂度o(nlog2 n)的算法进行排序,然后依次将数据元素依次插入链表,此时的时间复杂度o(nlog2 n),显然,是以空间换时间
##3.反向输出带头结点的单链表
思路1:采用栈的思想,用递归实现

viod L_print(Linklist &L){
	if(L->next!=NULL) {
		L_print(L->next);
	}
	print(L->data); //输出函数 
} 

思路2:采用就地逆置,然后遍历打印(代码在逆置处给出)
##4.将带头节点的单链表逆置
思路1:将头结点摘下,然后从第一个结点开始,依次头插法建立单链表,然后直至最后一个结点,over

Linklist Revrese(Linklist &L){
	LNode *p,r; //p为工作指针,r为p的后继,以防断链
	p=L->next;  //从第一个数据结点开始
	L->next=NULL; //摘头结点 
	while(p!=NULL){|
	  r=p->next; //
	  p->next=L->next; //p插到 l 后面 
	  L->next=p;
	  p=r; 
	} 
	return L;
} 

评价 :此算法时间复杂度o(n),空间复杂度o(1)
思路2:不断遍历链表,将后一个节点的next指向前一个节点
最后头节点挂到原链表的尾部

Linklist Reverse(Linklist &L){
    LNode *p=L,*q,*pr; //pr 指向待转置结点的下一个结点
    p=L->next ;
    L->next =NULL; //摘除头节点 
    q=NULL;  
    while(p){
        pr=p->next;
        p->next=q; //后一个节点的next指向前一个节点
        q=p;   //尾指针为空 
        p=pr;  //指针后移 
     } 
     L->next =q; //头节点挂到原链表的尾部
 } 

评价 :复杂度与思路一样
##5.找两单链表的公共结点
思路:分别遍历两个链表,得到两个链表的长度,并求差。在长的链表先遍历长度之差个结点,然后同步遍历,直到找到相同结点,或者一直到链表结束

Linklist Serach_Common(Linklist L1,Linklist L2){
	int len1=Length(L1),len2=Length(L2);
	Linklist longlist,shortlist;
	if(len1>len2){ 
		longlist=L1->next;
		shortlist=L2->next;
		dist=len1-len2; 
	}else{
		longlist=L2->next;
		shortlist=L1->next;
		dist=len2-len1; 
	}
	while(dist--)
		longlist=longlist->next;// 表长的先遍历dist步 
		
	while(longlist!=NULL){ //同步遍历 
		if(longlist==shortlist)
		  return longlist; 
		else{
			longlist=longlist->next;
			shortlist=shortlist->next;
		}
	}//while
	return NULL;
}

评价 :时间复杂度O(len1+len2)
##7.输出单链表中倒数第k个结点
思路:双指针,先让其中一个指针走k步,然后同步走,一遍扫描即可完成

bool Search(Linklist &L,int k){
	LNode *p=L->next,*q=L->next;
	int count=0;
	while(!p){
		if(cout<k) count++l; //先 p 移动 k 步 ,之后同步移动 p,q 
		else q=q->next;
		p=p->next;
	}
	if(count<k) return false;
	else cout<<q->data<<endl;
	return true; 
}	

##6.奇偶链表,即奇序号结点放前面,偶序号结点放后面(出自Leetcode)
例如:1,输出1
1,2,输出1,2
1,2,3 输出1,3,2;
1,2,3,4 输出1,3,2,4 以此类推
思路:奇偶结点交替存在,奇号结点链接的总是偶的下一个结点,而偶号结点链接的总是奇的下一个结点,由此可在遍历原单链表过程完成迭代

Linklist Function(Linklist &L){  //AC code
	LNode *odd=L->next;    //链接奇序号结点 
	LNode *even=odd->next; //链接偶序号结点
	LNode *Even=even;
	while(odd->next && even->next ){ //链表结点数超过两个输出才发生变化 
		odd->next=even->next;       //奇号结点链接的总是偶的下一个结点 
		odd=even->next ;            // 奇号结点后移两部 
		even->next=odd->next;       //偶号结点链接的总是奇的下一个结点
		even=odd->next ;            // 偶号结点后移两部 
	}
	odd->next=Even;     //偶数号结点头链接到奇数号结点尾部 
	return L;
} 

评价:一边遍历即可完成,时间复杂度o(n),空间复杂度o(1)
##7.求链表的中位数(不带头结点)
例如:1,输出 1
1,2,输出 1
1,2,3 输出 2 以此类推
思路:采用双指针,快慢链表,quick走两步,slow走一步,quick走到头,slow则走到中位数处

int Getmin( Linklist L){ //AC code
	LNode *quick=L;
	LNode *slow=L;
	if(slow==NULL) return NULL;
	while(quick->next !=NULL){
		if(quick->next->next !=NULL){
			slow=slow->next ;
			quick=quick->next->next ;
		}
		else{
			quick=quick->next ;
		}
	}
	return (slow->data );
}

##8.假设A,B链表递增有序(带头结点),求A,B的公共结点,要求不破坏A,B的结点
思路:表A,B都有序,可从A,B第一个元素开始依次比较A,B两表元素,若俩元素不相等,小的对应指针后移,若元素值相等,创建一个值等于俩结点的元素值的新结点,使用尾插法插入到新的链表中,并且两个原表指针后移一位,直到其中一个遍历到表位

void Get_Common(Linklist A,Linklist B){
	LNode *p=A->next,*q=B->next,*r,*s;
	Linklist C=new LNode ; //创建表 C 
	r=C;
	while(p!=NULL && q!=NULL){
		if(p->next <q->next ) //A 当前元素小,指针后移 
		  p=p->next ;
		else if(p->next >q->next) //B 当前元素小,指针后移
		  q=q->next ; 
		else{                     // 找到公共结点 
			s=new LNode;
			s->data =p->data ;  //尾插法插入*s结点 
			r->next=s;
			r=s;
			p=p->next ;  //A,B继续向后扫描 
			q=q->next ;
		}	
	}
	r->next =NULL; // 置 C 尾结点指针为空 
} 

##9.假设A,B链表递增有序(带头结点),编写函数,求A,B的交集,放于A链表中
思路:采用归并思想,设置两个工作指针pa,pb,对链表扫描,只有同时存在在俩集合中的元素才链接到结果表中且仅保留一个,其他结点全部释放。当一个链表遍历完毕,释放另一个表中的全部结点。

//AC 函数
Linklist Union(Linklist la,Linklist lb){
	LNode *pa=la->next ,*pb=lb->next ;
	LNode *pc=la;            //结果表中当前合并结点的前驱指针;
	LNode *u;              // u指针用于指向待释放结点空间 
	while(pa && pb){
		if(pa->data ==pb->data ){
			pc->next =pa;
			pc=pa;
			pa=pa->next ;
			u=pb;        
			pb=pb->next ;
			delete pb; 
		}else if(pa->data <pb->data ){
			u=pa;
			pa=pa->next ;
			delete u;
		}else {
			u=pb;
			pb=pb->next;
			delete pb;
		}
	}
	while(pa){  // B 遍历完, A 未结束 
	    u=pa;
	    pa=pa->next ;
	    delete u;
	}
	while(pb){
		u=pb;
		pb=pb->next ;
		delete pb;
	}
	pc->next =NULL; //置结果表的尾指针为空 
	delete lb; //释放 B 的头结点
	return la;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZCAIHUI_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值