線性表之連結串列複習(僅王道單鏈表題目)
阿新 • • 發佈:2018-12-25
考研408複習,如發現任何錯誤,請私聊,不勝感謝
單鏈表程式碼已更新完畢。
如下:
#include <iostream> #include <algorithm> #include <string> #include <cmath> #include <iomanip> #include <cstring> using namespace std; typedef struct LNode { int data; LNode *next; }Lnode, *Linklist; ///逆序建立連結串列 Linklist CreatepositiveLinklist(Linklist &head, int n) { head = new Lnode; head->next = NULL; for(int i=0;i<n;++i) { Linklist p = new Lnode; cin>>p->data; p->next = head->next; head->next = p; } return head; } ///正序建立連結串列 Linklist CreateNegativeLinklist(Linklist &head, int n) { Linklist tail; head = new Lnode; head->next = NULL; tail = head; for(int i=0;i<n;++i) { Linklist p = new Lnode; cin>>p->data; p->next = NULL; tail->next = p; tail = p; } return head; } ///列印連結串列 void print_Linklist(Linklist head) { if(head->next == NULL) { cout<<"The Linklist is NULL !"<<endl; return; } while(head->next->next) { cout<<head->next->data<<" "; head = head->next; } cout<<head->next->data<<endl; } ///按下標查詢結點 Lnode *Find_Lnode_byid(Linklist head, int key) { if(key == 0) return head; if(key < 1) return NULL; int num = 1; head = head->next; while(head && num < key) { head = head->next; num++; } return head; } ///在position處插入節點值為key的元素 void Insert_Lnode(Linklist &head, int position, int key) { if(position <= 0) { cout<<"輸入不合法,插入失敗!"<<endl; return; } Linklist p = Find_Lnode_byid(head, position-1); Linklist temp = new Lnode; temp->data = key; temp->next = p->next; p->next = temp; } ///刪除位置為position的節點 void Delete_Lnode(Linklist &head, int position) { if(position <= 0) { cout<<"The input is ERROR!, delete failed!"<<endl; return; } Linklist p = Find_Lnode_byid(head, position); Linklist q = p->next; p->next = q->next; } ///求連結串列長度 int Linklist_length(Linklist head) { if(head->next == NULL) return 0; int num = 0; while(head->next) { num++; head = head->next; } return num; } ///以下為一些綜合應用分析題,具有詳細題目描述 ///1.設計一個遞迴演算法,刪除不帶頭節點的單鏈表L中所有值為x的節點。 void The_first_problem(Linklist &head, int key) { if(head == NULL) return; if(head->data == key) { Linklist p = head; head = head->next; free(p); The_first_problem(head, key); } else The_first_problem(head->next, key); } ///這裡做一個理解說明:函式進行遞迴呼叫時,只是將head進行next操作,並沒有改變被刪除節點的前驅結點的next指向,疑似斷鏈操作 ///其實不然,這裡head為呼叫該函式的外層head->next,故這裡實現了head->next=head-next->next的造作過程。 ///2.在帶頭節點的單鏈表L中,刪除所有值為x的節點,並釋放其空間,假設值為x的節點不唯一。 Linklist The_second_problem(Linklist &head, int x) { Linklist q = head; Linklist p = head->next; while(p) { if(p->data == x) { q->next = p->next; free(p); p=q->next; } else { p=p->next; q=q->next; } } return head; } ///3.設L為帶頭節點的單鏈表,編寫演算法實現從尾到頭反向輸出每個節點的值 void The_third_problem1(Linklist head)///利用輔助空間解決問題 { int *temp = new int[Linklist_length(head)]; Linklist p = head->next; for(int i=0;i<Linklist_length(head); ++i, p=p->next) { temp[i] = p->data; } for(int i=Linklist_length(head)-1; i>0; --i) cout<<temp[i]<<" "; cout<<temp[0]<<endl; } void The_third_problem2(Linklist head)///使用遞迴思想解決問題 { if(head->next) The_third_problem2(head->next); cout<<head->data<<" "; } ///4.試編寫在帶頭節點的單鏈表L中刪除一個最小值節點的高效演算法(假設最小值節點是唯一的) Linklist The_four_problem(Linklist &head) { ///儲存最小值節點的位置及其前驅位置 Linklist q = head, p=head->next; Linklist mixn = p, mixnpre = q; while(p) { if(p->data < mixn->data) { mixn = p; mixnpre = q; } p = p->next; q = q->next; } mixnpre->next = mixn->next; free(mixn); return head; } ///5.試編寫演算法將帶頭結點的單鏈表就地逆置,所謂就地是指輔助空間複雜度為O(1) Linklist The_five_problem1(Linklist &head) { Linklist p = head->next; Linklist q = p->next; head->next = NULL; while(p) { p->next = head->next; head->next = p; p = q; if(q) q = q->next; } return head; } Linklist The_five_problem2(Linklist &head) { Linklist pre, p=head->next, r=p->next; p->next = NULL; while(r) { pre = p; p = r; r = r->next; p->next = pre; } head->next = p; return head; } ///6.有一個帶頭節點的單鏈表L,設計一個演算法,使其元素遞增有序 ///願你閱盡千帆,歸來仍是少年 Linklist The_six_problem(Linklist &head) { ///採用插入排序思想,即構造一個單鏈表,然後遍歷L,每走一個節點,插入一個節點。 Linklist p = head->next, r = p->next; p->next = NULL; p = r; r = r->next; while(p) { Linklist temp = head->next, tempre = head; while(tempre) { if(temp == NULL) { tempre->next = p; p->next = NULL; break; } if(p->data < temp->data) { p->next = temp; tempre->next = p; break; } temp = temp->next; tempre = tempre->next; } if(r) { p = r; r = r->next; } else break; } return head; } ///7.設在一個帶表頭節點的單鏈表L中所有元素節點的資料值無序,試編寫一個函式,刪除表中所有介於給定的兩個值之間的元素 ///人生一棋局,無法跳脫,終究是棋子。 Linklist The_seven_problem(Linklist &head, int a, int b) { Linklist p = head->next; Linklist q = head; while(p) { if(p->data >= a && p->data <= b) { q->next = p->next; free(p); p = q->next; } else { p = p->next; q = q->next; } } return head; } ///8.給定兩個單鏈表,編寫演算法找出兩個連結串列的公共節點 ///虛無縹緲者,是否虛幻。 Linklist The_eight_problem(Linklist head1, Linklist head2) { ///明確公共節點的定義,即如果兩個連結串列擁有公共節點,那麼在該節點之後的所有節點都是重合的,即他們最後一個節點必然是重合的。 int len1 = Linklist_length(head1), len2 = Linklist_length(head2); Linklist longlist, shortlist; int dist = abs(len1-len2);///兩表長之差 if(len1 > len2) { longlist = head1->next; shortlist = head2->next; } else { longlist = head2->next; shortlist = head1->next; } while(dist--) { longlist = longlist->next; } while(longlist) { if(longlist == shortlist) return longlist; longlist = longlist ->next; shortlist = shortlist ->next; } return NULL; } ///9.給定一個帶頭節點的單鏈表,按照遞增次序輸出單鏈表中各節點的資料元素,並釋放節點所佔的儲存空間。(不允許使用陣列做輔助空間) ///向來歷史都是由強者書寫 Linklist The_nine_problem(Linklist &head) { ///巢狀雙重迴圈,遍歷一次找到最小值輸出並釋放節點空間 while(head->next) { Linklist p = head->next; Linklist pre = head; Linklist mixn = p, mixnpre = pre; while(p) { if(p->data < mixn->data) { mixn = p; mixnpre = pre; } else { p = p->next; pre = pre->next; } } cout<<mixn->data<<endl; mixnpre->next = mixn->next; free(mixn); } return head; } ///10.將一個帶頭節點的單鏈表A分解為兩個帶頭結點的單鏈表的A和B,是的A表中元素為原表奇數序號的元素,B表中元素為原表偶數序號的元素,且保持其相對順序不變。 ///逆風翻盤,向陽而生 void The_ten_problem(Linklist &head, Linklist &head1, Linklist &head2) { Linklist tail2; head2 = new Lnode; head2->next = NULL; tail2 = head2; Linklist tail1; head1 = new Lnode; head1->next = NULL; tail1 = head1; Linklist p = head->next; int len = Linklist_length(head); for(int i=1;i<=len;i++) { if(i%2) { tail1->next=p; tail1 = p; } else { tail2->next = p; tail2 = p; } p = p->next; } tail1->next = NULL; tail2->next = NULL; } ///11.設C={a1, b1, a2, b2,......an, bn}為線性表,採用帶頭節點的單鏈表存放,設計一個就地演算法,使A={a1, a2, ...an},B={bn, ...b2, b1} ///與上題思路相同,只不過B單鏈表改成尾插法。 ///12.在一個遞增有序的線性表中,有數值相同的元素存在,儲存方式為單鏈表,設計演算法去掉數值相同的元素,是表中不存在相同元素。 Linklist The_twelve_problem(Linklist &head) { Linklist p = head->next; Linklist q = p->next; while(q) { if(p->data==q->data) { while(p->data == q->data) { if(q->next) q = q->next; else break; } if(q->next) p->next = q; else p->next = q->next; } p=p->next; q=q->next; } return head; } ///13.假設有兩個按元素值遞增次序排列的線性表,均以單鏈表形式儲存,歸併為一個按照元素值遞減的=次序排列的單鏈表 ///並要求利用原來兩個單鏈表節點存放歸併後的單鏈表 Linklist The_thirteen_problem(Linklist &head1, Linklist &head2) { ///從小開始比較,採用逆序建連結串列方法 Linklist p = head1->next; Linklist q = head2->next; Linklist r; head1->next = NULL; while(p && q) { if(p->data < q->data) { r = p->next; p->next = head1->next; head1->next = p; p = r; } else { r = q->next; q->next = head1->next; head1->next = q; q = r; } } if(p) { q = p; } while(q) { r = q->next; q->next = head1->next; head1->next = q; q = r; } free(head2); return head1; } ///14.設A和B是兩個單鏈表(帶頭節點), 其中元素遞增有序,設計一個演算法從A和B中公共元素產生單鏈表C,要求不破壞A和B的節點 Linklist The_fourteen_problem(Linklist &head1, Linklist &head2) { Linklist head = new Lnode; head->next = NULL; Linklist p = head1->next; Linklist q = head2->next; Linklist r = head; while(p && q) { if(p->data <q->data) p=p->next; else if(p->data > q->data) q = q->next; else { Linklist s; s = new Lnode; s->data = p->data; s->next = NULL; r->next = s; r = s; p=p->next; q=q->next; } } return head; } ///15.已知兩個連結串列A和B分別表示兩個集合,其元素遞增排列。編制函式,求A和B的交集,並存放於A連結串列之中 Linklist The_fifteen_problem(Linklist &head1, Linklist &head2) { ///較為簡單的歸併演算法,給出王道演算法 Linklist p = head1->next; Linklist q = head2->next; Linklist c = head1, u; while(p && q) { if(p->data == q->data) { c ->next = p; c=p; p=p->next; u = q; q=q->next; free(u); } else if(p->data < q->data) { u = p; p=p->next; free(u); } else { u = q; q=q->next; free(u); } } while(p) { u = p; p=p->next; free(u); } while(q) { u = q; q=q->next; free(u); } c->next=NULL; free(head2); return head1; } ///16.兩個連續子序列,判斷b是否為a的連續子序列 bool The_sixteen_problem(Linklist &head1, Linklist &head2) { Linklist p = head1->next; Linklist q = head2->next; Linklist pre = p; while(p && q) { if(q->data == p->data) { q = q->next; p = p->next; } else { pre = pre->next; p = pre; q = head2->next; } } if(q == NULL) return true; return false; } ///21.單鏈表,查詢連結串列中倒數第k個位置上的節點,若查詢成功,輸出資料並返回1,否則只返回0 bool The_twentyone_problem(Linklist head, int k) { ///演算法思想,p,q同時指向第一個元素,p先開始移動,當p移動到第k個元素時,q之後與p同步向後移動 ///這樣當p移動到最後一個元素時,q移動到倒數第k個元素 Linklist p = head->next; Linklist q = p; int num = 1; while(p) { if(num <= k) { cout<<"xunhuan "<<p->data<<endl; p=p->next; num++; continue; } cout<<"p: "<<p->data<<endl; p = p->next; q = q->next; } if(num <= k) return 0; cout<<q->data<<endl; return 1; } ///22.單鏈表,找出兩個連結串列共同字尾的起始位置。說明時間複雜度。 ///與第8題相仿,不予贅述 ///23.單鏈表,刪除絕對值相等的節點,僅保留第一次出現的節點。 Linklist The_twentythree_problem(Linklist &head, int n) { int *temp = new int[n+1]; Linklist p=head->next, pre = head; memset(temp, 0, n+1); while(p) { int data = p->data>0?p->data:-p->data; if(temp[data] == 0) { p=p->next; pre = pre->next; temp[data] = 1; } else { pre->next = p->next; free(p); p = pre->next; } } return head; } int main() { ios::sync_with_stdio(false); Linklist head; int n; cin>>n; head = CreateNegativeLinklist(head, n); /* Linklist head1, head2; int n, m; cin>>n>>m; head1 = CreateNegativeLinklist(head1, n); head2 = CreateNegativeLinklist(head2, m); print_Linklist(head); cout<<Find_Lnode_byid(head, 3)->data<<endl; Insert_Lnode(head, 1, 999); print_Linklist(head); cout<<Linklist_length(head)<<endl; //The_first_problem(head, 5); //print_Linklist(head); //cout<<Linklist_length(head)<<endl; The_second_problem(head, 5); print_Linklist(head); cout<<Linklist_length(head)<<endl; The_third_problem1(head); The_third_problem2(head->next); head = The_four_problem(head); print_Linklist(head); head = The_five_problem2(head); print_Linklist(head); head = The_seven_problem(head, 2, 5); The_ten_problem(head, head1, head2); print_Linklist(head1); print_Linklist(head2); head = The_twelve_problem(head); print_Linklist(head); bool flag = The_sixteen_problem(head1, head2); cout<<flag<<endl; bool flag = The_twentyone_problem(head, 3); cout<<flag<<endl;*/ head = The_twentythree_problem(head, 20); print_Linklist(head); return 0; }