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; }