1. 程式人生 > 實用技巧 >01-連結串列操作整理

01-連結串列操作整理

//連結串列操作整理
#include<vector>
#include<iostream>
#include<stack>
using namespace std;
//連結串列類的定義
struct node{
    int val;
    node *next;
    node():val(-1),next(NULL){};
    node(int val):val(val),next(NULL){};
    node(int val,node *next):val(val),next(next){}
};

//連結串列的遍歷
void traverse(node *head){
    node 
*p=head; while(p){ cout<<p->val<<" "; p=p->next; } cout<<endl; } //連結串列的初始化 node* initial(vector<int> nums){ node *head=new node(-1); //初始化時可以首先建立一個假頭節點,給定值-1,返回的時候返回vhead->next即可 node *p=head; for(auto x:nums){ node *tmp=new
node(x); p->next=tmp; p=tmp; } return head->next; } //連結串列在後面新增節點 void add_back(node *p,int val){ //連結串列在後面新增節點,先建立新節點,讓p->next等於新節點,然後p後移p=p->next,進入下一輪迴圈 node *tmp=new node(val); p->next=tmp; p=p->next; } //連結串列在前面新增節點 void add_front(node *p,int
val){ //連結串列在前面新增節點,先建立新節點,讓新節點指向p,然後p前移,即tmp->next=p;p=tmp; node *tmp=new node(val); tmp->next=p; p=tmp; } //連結串列翻轉 node* reverse(node *head){ //連結串列翻轉需要三個節點,一個是pre,最開始是空節點,後來不斷作為p節點的前一個節點,每次p節點更新之後,pre即變成p,即pre=p;p=p->next; //另一個節點是cur,最開始為定值為head,還需要一個nxt節點,記錄cur的next節點,因為cur每次迴圈裡要更新cur->next=pre;pre=cur;cur=nxt;要用nxt記錄下cur正序的後節點 //迴圈條件是cur,當正序的cur->next==NULL時,下一輪迴圈cur為NULL,此時迴圈結束,pre為正序連結串列最後一個節點,nxt也為NULL //最後返回的節點是pre,因為pre是正序連結串列最後一個節點,也就是翻轉後的頭節點。而cur和nxt此時都為NULL node *pre=NULL; node *cur=head; node *nxt; while(cur){ nxt=cur->next; cur->next=pre; pre=cur; cur=nxt; } return pre; } //連結串列刪除重複節點,保留一個 node* deletedupl(node *head){ node *vhead=new node(-1); vhead->next=head; node *p=vhead->next; node *pre=vhead; //用一個vhead,虛擬頭節點,可以省去對head頭節點為重複節點時的誤判 //返回時返回的是vhead->next while(p){ if(p->next&&p->val==p->next->val){ while(p->next&&p->val==p->next->val){ p=p->next; } //這裡的迴圈結束之後,p位於重複節點的最後一個,此時因為要保留一個,所以不用後移 //pre->next=p; //pre=p; //p=p->next; }else{ //此時的pre節點在重複節點前一個節點位置,p在最後一個重複節點位置,只需要把pre與p連線起來,再把pre移到p的位置,p後移一位即可 pre->next=p; pre=p; p=p->next; } } return vhead->next; } //連結串列刪除重複節點,一個也不保留 node *deletedupl2(node *head){ node *vhead=new node(-1); vhead->next=head; node *p=vhead->next; node *pre=vhead; while(p){ if(p->next&&p->val==p->next->val){ while(p->next&&p->val==p->next->val){ p=p->next; } p=p->next; //這是與上一個刪除重複節點但保留一個唯一不同之處,當迴圈結束時,p處在重複節點的最後一個,後移一位意味著重複節點一個也不保留 //在這裡不能直接進行拼接,是因為可能會有很多組重複節點 //pre->next=p; //pre=p; //p=p->next; }else{ //此時的pre節點位於重複節點的前一位,p位於重複節點的後一位,連線pre與p即可掠過所有重複節點 pre->next=p; pre=p; p=p->next; } } return vhead->next; } //判斷連結串列是否有環 //可以採用set來判定是否存在重複,也可以使用雙指標方法 //slow指標最開始指向head節點,fast指標最開始指向head節點的下一個節點,即head->next //迴圈條件既需要保證slow及fast指標存在,又需要保證fast->next存在,因為fast指標一次要走兩步 //另一個迴圈條件是fast指標與slow指標不相等 -> while(slow&&fast&&fast->next&&fast!=slow) //如果連結串列無環,fast指標會先到達末尾,此時slow指標與fast指標不相等 //如果連結串列有環,則fast指標會向套圈一樣最後趕上slow指標,二者相等 //因此迴圈結束後的返回條件可以是return slow==fast; bool circle(node *head){ node *slow=head; node *fast=head->next; //最開始讓fast=head->next,可以省去在迴圈條件中判斷初始狀況的特例 while(slow&&fast&&fast->next&&fast!=slow){ slow=slow->next; fast=fast->next->next; } return fast==slow; } //兩個有序連結串列的合併 node *merge(node *h1,node *h2){ if(!h1&&!h2){ return NULL; } if(!h1){ return h2; } if(!h2){ return h1; } node *new_head=new node(-1); node *p=new_head; while(h1&&h2){ if(h1->val<=h2->val){ p->next=h1; p=p->next; h1=h1->next; }else{ p->next=h2; p=p->next; h2=h2->next; } } while(h1){ p->next=h1; p=p->next; h1=h1->next; } while(h2){ p->next=h2; p=p->next; h2=h2->next; } return new_head->next; } //刪除連結串列指定值節點 node* deletenode(node *head,int val){ node *vhead=new node(-1); vhead->next=head; node *p=vhead->next; node *pre=vhead; while(p){ if(p->val==val){ while(p->next&&p->next->val==val){ p=p->next; } p=p->next; }else{ pre->next=p; pre=pre->next; p=p->next; } } return vhead->next; } //連結串列求和 //連結串列反向儲存數字 node *add(node *h1,node *h2){ int carry=0; node *nh=new node(-1); node *p=nh; while(h1&&h2){ int tmp=h1->val+h2->val+carry; if(tmp>=10){ tmp%=10; carry=1; }else{ carry=0; } node *t=new node(tmp); p->next=t; p=p->next; h1=h1->next; h2=h2->next; } while(h1){ int tmp=h1->val+carry; if(tmp>=10){ tmp%=10; carry=1; }else{ carry=0; } node *t=new node(tmp); p->next=t; p=p->next; h1=h1->next; } while(h2){ int tmp=h2->val+carry; if(tmp>=10){ tmp%=10; carry=1; }else{ carry=0; } node *t=new node(tmp); p->next=t; p=p->next; h2=h2->next; } if(carry){ node *t=new node(1); p->next=t; } return nh->next; } //連結串列求和 //連結串列正向儲存數字 node* add2(node *h1,node *h2){ stack<int> stk1; stack<int> stk2; while(h1){ stk1.push(h1->val); h1=h1->next; } while(h2){ stk2.push(h2->val); h2=h2->next; } int carry=0; int tmp=stk1.top()+stk2.top()+carry; stk1.pop(); stk2.pop(); if(tmp>=10){ tmp%=10; carry=1; }else{ carry=0; } node *nh=new node(tmp); while(!stk1.empty()&&!stk2.empty()){ int tmp=stk1.top()+stk2.top()+carry; stk1.pop(); stk2.pop(); if(tmp>=10){ tmp%=10; carry=1; }else{ carry=0; } node *t=new node(tmp); t->next=nh; nh=t; } while(!stk1.empty()){ int tmp=stk1.top()+carry; stk1.pop(); if(tmp>=10){ tmp%=10; carry=1; }else{ carry=0; } node *t=new node(tmp); t->next=nh; nh=t; } while(!stk2.empty()){ int tmp=stk2.top()+carry; stk2.pop(); if(tmp>=10){ tmp%=10; carry=1; }else{ carry=0; } node *t=new node(tmp); t->next=nh; nh=t; } if(carry){ node *t=new node(1); t->next=nh; nh=t; } return nh; } //迴文連結串列 bool huiwen(node *head){ node *vhead=new node(-1); vhead->next=head; node *slow=vhead; node *fast=vhead; while(fast&&fast->next){ fast=fast->next->next; slow=slow->next; } node *p=slow->next; slow->next=NULL; node *pre=NULL; node *cur=p; node *nxt; while(cur){ nxt=cur->next; cur->next=NULL; pre=cur; cur=nxt; } while(pre&&head){ cout<<pre->val<<" "<<head->val<<endl; if(pre->val!=head->val){ return false; }else{ pre=pre->next; head=head->next; } } return true; } //快速找到連結串列的中間節點 node* find_mid(node *head){ node *vhead=new node(-1); vhead->next=head; node *slow=vhead; node *fast=vhead; while(fast&&fast->next){ fast=fast->next->next; slow=slow->next; } return slow; } //快速找到連結串列倒數第k個節點 node* kthnode(node *head,int k){ node *slow=head; node *fast=head; while(k--){ fast=fast->next; } while(k){ slow=slow->next; fast=fast->next; } return slow; } //每隔k個翻轉連結串列 node *k_rev(node *head,int k){ int r=0; node *vhead=new node(-1); int t=k; vhead->next=head; node *pre=vhead; node *p=head; while(p){ if(r==1){ node *pv=NULL; node *cur=p; node *nxt; for(int i=0;cur&&i<k;i++){ //這裡需要同時判斷cur是否還存在,如果cur不存在,即==NULL,不影響後面語句。但是如果不加該條件,會有段錯誤 nxt=cur->next; cur->next=pv; pv=cur; cur=nxt; } pre->next=pv; p->next=nxt; r=0; pre=p; p=p->next; }else{ for(int i=0;p&&i<k;i++){ pre->next=p; //這一句和下一句都是不能少的,不然vhead會串聯不到後面沒有翻轉的部分 pre=pre->next; //* p=p->next; } r=1; //不能忘記改成1 } } return vhead->next; } int main(){ vector<int> n1={1,2,3,4,5,6,7,8,9,10}; vector<int> n2={2,3,4,5,6,7,8,9,10}; node *h1=initial(n1); //node *h2=initial(n2); traverse(h1); //traverse(h2); //node *p=add(h1,h2); //traverse(p); node *p=kthnode(h1,5); cout<<k->val<<endl; return 0; }