面试算法 牛客题目 链表的奇偶重排

1.题目:   链表的奇偶重排
描述
给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。
注意是节点的编号而非节点的数值。

数据范围:节点数量满足 0 < n< 10^5
5节点中的值都满足 0 <val < 10000
要求:空间复杂度 O(n),时间复杂度 O(n)


2.算法:
1.暴力算法:数据搞出来重新赋值 

2.双指针算法 , 指针连接 


3.算法思想:

暴力算法:把单数  , 和偶数的节点的值  分别 取出来  存入动态数组。 在 给链表重新赋值

.双指针算法 , 指针连接 

如下图所示,第一个节点是奇数位,第二个节点是偶数,第二个节点后又是奇数位,因此可以断掉节点1和节点2之间的连接,指向节点2的后面即节点3,如红色箭头。如果此时我们将第一个节点指向第三个节点,就可以得到那么第三个节点后为偶数节点,因此我们又可以断掉节点2到节点3之间的连接,指向节点3后一个节点即节点4,如蓝色箭头。那么我们再将第二个节点指向第四个节点,又回到刚刚到情况了。

具体做法:

  • step 1:判断空链表的情况,如果链表为空,不用重排。
  • step 2:使用双指针odd和even分别遍历奇数节点和偶数节点,并给偶数节点链表一个头。
  • step 3:上述过程,每次遍历两个节点,且even在后面,因此每轮循环用even检查后两个元素是否为NULL,如果不为再进入循环进行上述连接过程。
  • step 4:将偶数节点头接在奇数最后一个节点后,再返回头部。

    4.代码:

    /*************************************************
    作者:She001
    时间:2022/10/2
    题目:   链表的奇偶重排
    描述
    给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。
    注意是节点的编号而非节点的数值。
    
    数据范围:节点数量满足 0 < n< 10^5
    5
     ,节点中的值都满足 0 <val < 10000≤
    要求:空间复杂度 O(n),时间复杂度 O(n)
    
    
    
    ***************************************************/
    //算法:
    //1.暴力算法:数据搞出来重新赋值 
    //2.双指针算法 , 指针连接 
    
    #include<bits/stdc++.h>
    using namespace std;
    typedef struct node
    {
    	int i;
    	node *next;	
    }; 
    
    
    void print(node * head)//打印链表 
    {
    	node* pp= head;//复制头节点 
    	while(pp!=NULL)//判断这个节点是否为空  链表是否结束 
    	{
    		cout<<pp->i<<"  ";
    		pp=pp->next;//指向下一个 
    	}
    	cout<<endl;
    	
    }
    
    
    
    int lianbiao_num(node * head)//函数的作用 返回链表的个数
    {
    	int i=0;
    	node* pp=head;
    	while(pp!=NULL)
    	{
    		i++;
    		pp=pp->next;	
    	}
    	//cout<<"链表中节点的个数: "<<i<<endl;
    	return i;	
    } 
    
    
    node * reverseList(node* head)//翻转链表 
    {
    	if(head==NULL)
    	{
    		return NULL;	
    	}	
    	node * a = head;
    	node * b = NULL;
    	while(a!=NULL)
    	{
    		node * c = a->next;
    		a->next=b;
    		b=a;
    		a=c;
    	}
    	return b;	
    } 
    
    
    //1.暴力算法:
    //
    node *  fangfa_1(node * head)
    {
    	int a= lianbiao_num(head);//计算链表的长度 
    	if(head==NULL ||a==1 || a==2)
    	{
    		return head;	
    	}
    	vector<int> q;//建立一个动态数组 储存 数据
    	node * a1=head;//单数的链表节点
    	node * a2=head->next;//双数的链表的节点
    	
    	while(a1!=NULL) //这个位置的节点有数据,就需要记载在 动态数组里面 
    	{
    		q.insert(q.end(),a1->i);//存储单数节点数据
    		if(a1->next==NULL)//防止出现错误 
    		{
    			break;
    		}
    		else
    		{
    			a1=a1->next->next;  
    		}
    		
    	}
    	
    	while(a2!=NULL) 
    	{
    		q.insert(q.end(),a2->i);//存储单数节点数据
    		if(a2->next==NULL)//防止出现错误 
    		{
    			break;
    		}
    		else
    		{
    			a2=a2->next->next;  
    		}
    	}
    	a1=head;
    	vector<int>::iterator it =q.begin();//定义一个 遍历的工具    迭代器 
    	while(a1!=NULL) //重新赋值
    	{
    		a1->i=*it;
    		a1=a1->next;
    		it++;
    	} 
    	return head; //返回链表的头节点 
    	
    }
    
    
    
    //2.双指针算法 
    node*   fangfa_2(node* head)
    {
    	int a= lianbiao_num(head);//计算链表的长度 
    	if(head==NULL ||a==1 || a==2)
    	{
    		return head;	
    	}
    	node * a1=head;//链表的单数节点
    	node * a2=head->next;//链表的双数节点
    	node * a3=a2;//保存链表双数 节点的头节点 
    	while(a2!=NULL  && a2->next!=NULL)//这样保证了 a1 最后退出循环  不会等于  NULL  保证 a1 一定是一个有用的节点  因为 a1 在 a2 的后面 
    	{
    		a1->next=a2->next;//建立单数链表的连接 
    		a1=a1->next;//节点的变化 
    		a2->next=a1->next;//建立双数链表的连接 
    		a2=a2->next;//指向要建立连接的节点 
    	}
    	a1->next=a3;//链表的单数节点  与双数节点建立连接
    	 
    	return head;
    }  
    
    
    
    int main()
    {
    	
    	
    	//建立  第一个 单链表  
    	node *a1=new node;
    	node *a2=new node;
    	node *a3=new node;
    	node *a4=new node;
    	node *a5=new node;
    	node *a6=new node;
    	node *a7=new node;
    	node *a8=new node;
    	node *a9=new node; 
    	
    	a1->i=1;//链表节点的复制 
    	a2->i=2;
    	a3->i=3;
    	a4->i=4;
    	a5->i=5;
    	a6->i=6;
    	a7->i=7;
    	a8->i=8;
    	a9->i=9;
    	
    	
    	a1->next=a2;//链表的连接 
    	a2->next=a3;
    	a3->next=a4;
    	a4->next=a5;
    	a5->next=a6;
    	a6->next=a7;
    	a7->next=a8;
    	a8->next=a9;//a5 是 两个链表的节点 
    	a9->next=NULL;
    	
    	//node * k= fangfa_1(a1);
    	//print(k);
    	node * k1= fangfa_2(a1);
    	print(k1);
    	
    	
    	return 	0;
    } 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值