前言:
为了更好的自我监督,为了锻炼自己的代码能力,开始刷题,一共100道题,一天6道题,假期还剩下20天,还可以练完。
上午两道题 下午两道题 晚上两道题。
题目描述:
重排链表 算法思路:
(1)首先找到链表的中间结点
(2)对链表的后半部分进行逆序反转
(3)把链表的前半部分子链表与逆序后的后半部分子链表进行合并,合并的思路为:分别从两个 链表各取一个结点进行合并
main函数:
int main(){
ListNode *head=createByTail();
Solution().reorderList(head);
displayLink(head);
return 0;
}
首先要利用尾插法创建链表,在这里题目要求使用不带头结点的单链表进行操作,所以像之前的ListNode *head=new ListNode;head->next=NULL之类的代码不再使用,而是直接ListNode *head;head=NULL;即可,因为带头结点的单链表是肯定要new一个新的ListNode 但是无头结点就不用。
所以有以下代码:
ListNode *creatByTail(){
ListNode *head;
ListNode *p;
ListNode *tail;
int n=0,num;
int len;
cin>>len;
head=NULL;
while(n<len && cin>>num){
p=new ListNode;
p->val=num;
p->next=NULL;
n=n+1;
if(n==1){
head=p;
}
else{
tail->next=p;
}
tail=p;
}
return head;
}
创建链表之后就要对链表进行操作了,再来复习一下算法的思路:
(1)首先利用快慢指针找出链表的中间结点
(2)然后将中间结点之后的链表部分进行逆序反转操作
(3)将包含中间结点在内的前半部分链表作为list1,逆序之后的后部分链表作为list2,将list1和list2进行交叉合并即可。
首先是利用快慢指针找出链表的中间结点,原理就是快指针每次走两步,慢指针每次走一步,遍历链表,当fast->next=NULL或者fast->next->next==NUll的时候说明链表已经要遍历完,此时慢指针正好走到链表的中间位置。代码如下:
ListNode *middleNode(ListNode *head){
ListNode *fast=head;
ListNode *slow=head;
while(fast->next!=NULL && fast->next->next!=NULL){
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
利用上面的代码就可以找到链表的中间结点,找到之后我们说要将中间结点的后面部分链表进行逆序,逆序的思想我参考了这篇文章逆序思想
我觉得作者写的非常好,在这里我自己重新学习一遍。
逆序思想:
(1)如果是空链表即head==NULL的情况,直接返回。
(2)if head!=NULL;那么要利用三个指针,ListNode *prev=NULL;(用来指向前指针)
ListNode *curr=head;(用来指向当前指针)
ListNode *nextTemp=curr->next;(用来指向后指针)
(3)遍历链表,循环的判定因子是curr是否为NULL,为NULL表示达到链表结尾跳出循环,否则在链表中执行循环内逻辑:
将curr指向的当前结点的下一个结点指向prev,即curr->next=prev,此时prev=NULL,那么curr的下一个结点就为空了,表示它现在是最后一个结点了。然后将prev指针指向curr,将curr指向nextTemp,即prev=curr;curr=nextTemp;然后再进行下一次循环即可。
代码如下:
ListNode *reverseLink(ListNode *head){
ListNode *prev=NULL;
ListNode *curr=head;
while(curr!=NULL){
ListNode nextTemp=curr->next;
curr->next=prev;
prev=curr;
curr=nextTemp;
}
return prev;
}
将中间结点之后的链表进行逆序反转之后就要进行合并了,在合并之前来看看我们是如何将原本的一个链表变为两个链表的:
ListNode *mid=middleNode(head);
ListNode *list1=head;
ListNode *list2=mid->next;
mid->next=NULL;
list2=reverseList(list2);
}
首先找到中间结点mid,然后将原本链表的head赋值给list1,将mid->next赋值为list2,也就是将中间结点指向的下一个结点赋值为list2。然后将mid->next赋值为NULL,说明list1到mid处就完了,此时再反转list2即可。
来看最后的合并操作,合并操作非常简单,就是利用两个临时变量,一个用来遍历链表1中的元素,一个用来遍历链表2中的元素,首先将链表2的第一个元素插入到链表1的第一个元素后,然后将链表1的第二个元素插入到链表2的第一个元素后面,代码如下:
void mergeList(LixtNode *list1,ListNode *list2){
ListNode *list1_temp;
ListNode *list2_temp;
while(list1!=NULL && list2!=NULL){
list1_temp=list1->next;
list2_temp=list2->next;
list1->next=list2;
list1=list1_temp;
list2->next=list1;
list2=list2_temp;
}
}
完整代码如下:
#include<iostream>
using namespace std;
//重排链表 算法思路:
//(1)首先找到链表的中间结点
//(2)对链表的后半部分进行逆序反转
//(3)把链表的前半部分子链表与逆序后的后半部分子链表进行合并
//合并的思路为:分别从两个 链表各取一个结点进行合并
struct ListNode{
int val;
ListNode *next;
};
class Solution{
public:
void reorderList(ListNode *head){
if(head == NULL){
return;
}
ListNode *mid=middleNode(head);//找出链表的中间结点
ListNode *list1=head;
ListNode *list2=mid->next;
mid->next=NULL;
list2=reverseList(list2);
mergeList(list1,list2);
}
ListNode *middleNode(ListNode *head){
ListNode *slow =head;
ListNode *fast =head;
while(fast->next!=NULL && fast->next->next!=NULL){
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
ListNode *reverseList(ListNode *head){
ListNode *prev=NULL;
ListNode *curr=head;
while(curr!=NULL){
ListNode *nextTemp=curr->next;
curr->next=prev;
prev=curr;
curr=nextTemp;
}
return prev;
}
void mergeList(ListNode *list1,ListNode *list2){
ListNode *list1_temp;
ListNode *list2_temp;
while(list1!=NULL && list2!=NULL){
list1_temp=list1->next;
list2_temp=list2->next;
list1->next=list2;
list1=list1_temp;
list2->next=list1;
list2=list2_temp;
}
}
};
ListNode *createByTail(){
ListNode *head;
ListNode *p,*tail;
int n=0,num;
int len;
cin>>len;
head=NULL;
while(n<len && cin>>num){
p=new ListNode;
p->val=num;
p->next=NULL;
n=n+1;
if(n==1){
head=p;
}
else{
tail->next=p;
}
tail=p;
}
return head;
}
void displayLink(ListNode *head){
ListNode *p;
p=head;
cout<<"head-->";
while(p!=NULL){
cout<<p->val<<"-->";
p=p->next;
}
cout<<"tail\n";
}
int main(){
ListNode *head=createByTail();
Solution().reorderList(head);
displayLink(head);
return 0;
}