数据结构---C语言版 408 2019-41题代码版

题目:

2019 ( 单链表 )
41 .( 13 分)设线性表 L ( a 1 , a 2 , a 3 ,…… ,an2, a n 1 , a n ) 采用带头结点的单链表保存,链表中
的结点定义如下:
typedef struct node {
int data;
struct node* next;
} NODE
请设计一个空间复杂度为 O (1) 且时间上尽可能高效的算法,重新排列 L 中的各结点,
得到线性表 L   ( a 1 , a n , a 2 , a n 1 , a 3 , a n 2 ,…… )

 

思想:

读题发现本题主要实现前半部分顺序不变,后半部分变为逆序,且最后返回前后前后交叉的链表。

不妨 将前半部分和后半部分分开,单独处理后半部分,最后将后半部分插入里面。

所以:

1.将前半部分和后半部分分开-->即找到中间结点将链表一刀两断。

找中间结点---》不难想到双指针last、fast

这里一定要注意将last定义last=L->next;fast=L->next;!第一次写的时候忘定值了last,fast=L->next;这样last并未赋值后面last移动不了

双指针就是fast一下子移动两步,last一步一步走,当fast到终点的时候,last也就到中点了。(

但因为个树奇偶情况不同,所以fast需要移动一个判断一下,而只有移动两次的时候,last才移动,能保证一定在中间)

LinkList last,fast;
last=L->next;fast=L->next;	
while(fast){
		fast=fast->next;
		if(!fast) break;
		fast=fast->next;
		if(!fast) break;
		
		last=last->next;
		
	}

 这里一刀两断,方法太棒了,直接让last->next=NULL;斩断。

L2->next=last->next;
last->next=NULL;
2.单独处理后半部分

因为题目要求 空间复杂度为 O(1),所以考虑原地逆置。

原地逆置:其实就是把--->改为<---;然后原先第一个结点(L->next)的下一个设置为NULL,头结点后接最后一个节点

LinkList reverse(LinkList&L2) {
	if(!L2||!L2->next)	return L2;
	LinkList pre=L2->next;
	LinkList p=pre->next;
	LinkList last;
	while(p){
		last=p->next;
		p->next=pre;
		pre=p;
		if(!last) break;
		p=last;
	}
	L2->next->next=NULL;//链表的第一个结点的next要为NULL; 
	L2->next=p;
	return L2;
}
 3.第三步就是合并了,按照前后前后合并就可以。合并的时候,记得设置结点保存后面的一个结点
//链表合并 
void merge(LinkList &L,LinkList L2) {
	LinkList p1,p2;
	p1=L->next;
	p2=L2->next;
	while(p1&&p2){
		LinkList last1=p1->next;
		LinkList last2=p2->next;
		p1->next=p2;p2->next=last1;
		p1=last1;p2=last2;
	}
	if(p1) p1->next=NULL;
	if(p2) p2->next=NULL;
}

 代码汇总:

typedef struct node{
	int data;
	struct node* next;
}LNode,*LinkList; 
 //尾插法新建链表
LinkList creat_tail(LinkList &L){
	int x;
	scanf("%d",&x);
	L=(LNode*)malloc(sizeof(LNode));//创建头结点 
	LNode* tail;tail=L;
	while(x!=9999){
		LinkList s=(LNode*)malloc(sizeof(LNode));
		s->data=x;
		tail->next=s;
		s->next=NULL;
		tail=s;
		scanf("%d",&x);
	}
	return L;
} 

//找到中间节点--》双指针的运用,拆分巧妙 
void find_mid(LinkList L,LinkList&L2){
 	L2=(LNode*)malloc(sizeof(LNode));
 	LinkList last,fast;
	last=L->next;fast=L->next;
	
	while(fast){
		fast=fast->next;
		if(!fast) break;
		fast=fast->next;
		if(!fast) break;
		
		last=last->next;
		
	}
	
	L2->next=last->next;
	last->next=NULL;
 }
//原地逆置
LinkList reverse(LinkList&L2) {
	if(!L2||!L2->next)	return L2;
	LinkList pre=L2->next;
	LinkList p=pre->next;
	LinkList last;
	while(p){
		last=p->next;
		p->next=pre;
		pre=p;
		if(!last) break;
		p=last;
	}
	L2->next->next=NULL;//链表的第一个结点的next要为NULL; 
	L2->next=p;
	return L2;
}
//链表合并 
void merge(LinkList &L,LinkList L2) {
	LinkList p1,p2;
	p1=L->next;
	p2=L2->next;
	while(p1&&p2){
		LinkList last1=p1->next;
		LinkList last2=p2->next;
		p1->next=p2;p2->next=last1;
		p1=last1;p2=last2;
	}
	if(p1) p1->next=NULL;
	if(p2) p2->next=NULL;
}
//指针打印
void Print(LinkList L) {
	LNode* P=L->next;
	while(P){
		printf("%3d",P->data);
		P=P->next;
	}
}
int main(){
	LinkList L;
	creat_tail(L);
	Print(L);
	LinkList L2=NULL;
	printf("_____________\n");
	find_mid(L,L2);
	printf("_________________\n");
	Print(L);
	Print(L2);
	printf("__________________\n");
	L2=reverse(L2);
	Print(L2);
	printf("____________\n");
	merge(L,L2);
	free(L2);
	Print(L);
	printf("________________\n");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值