資料結構篇_程式設計思想板塊_第一章順序表和連結串列

Oten發表於2022-05-10
  • 程式設計思想板塊最主要的內容是資料結構經典題目及解答題目所需的程式設計思想,願對您能有所幫助
各資料結構程式名稱
順序表 Sqlist
連結串列結點 LinkList(結構體型別指標,malloc處不用加*)LNode(結構體型別物件)![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps60C8.tmp.jpg)
順序棧鏈式棧 SqStake,LiStake(結構體型別指標,malloc處不用加*)
順序佇列鏈式佇列 SqQueue,LinkQueue
順序串堆中串鏈式串KMP演算法中 SString,HString,LinkString,String
鏈式二叉樹線索二叉樹雙親表示法時的樹孩子兄弟表示法時的樹 BiTNode,*BiTree(指向根節點,下同)ThreadNode,*ThreadTree,PTree,CSNode,*CSTree
鄰接矩陣儲存圖鄰接表儲存圖圖遍歷 MGraph,ALGraph,Graph
順序查詢折半查詢 SSTable,SeqList

一、順序表和連結串列

① 若以線性表表示集合並進行集合的各種運算,應先對錶中元素進行排序

② 常考將兩個有序連結串列合成一個新的有序表

③ 在這一章中雜湊表的思想很常用

④ 注意:程式碼後記得要更新length值

⑤ 逆置的常見方法:

(1) 頭插法

(2) 遞迴

(3) 藉助棧

⑥ 連結串列中:

(1) 前插操作時:將待插入結點s依舊插入P後面,然後交換s和p的值,此時時間複雜度為O(1)

(2) 刪除結點p:將後繼結點的值賦給自己p,然後刪除後繼結點,此時時間複雜度為O(1)

(3) 若題目中只要求在時間上儘可能高效,則採用空間換時間的方法

1)順序表經典題目的程式設計思想

1. 對長度為n的順序表L,編寫一個時間複雜度為O(n)、空間複雜度為0(1)的演算法,該演算法刪除線性表中所有值為x的資料元素經典的順序表刪除元素的方法

思想:

① 用k記錄順序表L中不等於x的元素個數(即需要儲存的元素個數),邊掃描L邊統計k,並將不等於x的元數向前移動k個位置(初始k=0),最後修改L的長度

② 用k記錄順序表L中等於x的元素個數,邊掃描L邊統計k,並將不等於x的元素前移k個位置,最後修改L的長度

2. 從有序順序表中刪除所有其值重複的元素,使表中所有元素的值均不同若為無序的可用雜湊表解決

思想:

① 用類似於直接插入排序的思想,初始時將第一個元素視為非重複的有序表。之後依次判斷後面的元素是否與前面非重複有序表的最後一個元素相同,若相同,則繼續問後判斷,若個同,則插入前面的非重複有序表最後,直至判斷到表尾為止

3. 將兩個有序順序表合併為一個新的有序順序表,並由函式返回結果順序表

思想:

① 首先,按順序不斷取下兩個順序表表頭較小的結點存入新的順序表中。然後,看哪個表還有剩餘,將剩下的部分加到新的癩序表後面

4. 已知在一維陣列A[m+n]中依次存放兩個線性表(a,a2,...,am)和(b1,b2,b3,..,bn)。試編寫一個函式,將陣列中兩個順序表的位置互換,即將(b1,b2,b3,..,bn)放在(a,a2,...,am)的前面

思想:

① 

5.

思想:

6. 一個長度為L(L≥1)的升序序列S,處在第向上取整(L/2)個位置的數稱為S的中位數。例如,若序列S1=(11,13,15,17,19)則S1的中位數是15,兩個序列的中位數是含它們所有元素的升序序列的中位數。例如,若S2=(2,4,6,8, 20),則S1和S2的中位數是11.現在有兩個等長升序序列A和B,試設計一個在時間和空間兩方面都儘可能高效的演算法,找出兩個序列A和B的中位數

思想:

① 分別求兩個升序序列A、B的中位數,設為a和b,求序列A、B的中位數過程如下

(1) 若a<b,則捨棄序列A中較小的一半,同時捨棄序列B中較大的一半,要求兩次捨棄長度相等

(2) 若a>b、則捨棄序列A中較大的一半,同時捨棄序列B中較小的--半,要求兩次捨棄的長度相等

(3) 若a=b,則α或b即為所求中位數,演算法結束

(4) 在保留的兩個升序序列中,重複過程①、②、③,直到兩個序列中均只含一個元素時為止,較小者即為所求的中位數

7. 已知一個整數序列A=(a_0,a_1,...,a_(n-1)),其中0≤a_i<n(0≤i<n)。若存在a_p1=a_p2=...=a_pm=x且m>n/2(0≤P_k<n,1<=k<=m),則稱x為A的主元素。例如A=(0,5,5,3,5,7,5,5),則5為主元意;又如A=(0,5,5,3,5,1,5,7),則A中沒有主元素。假設A中的n個元素儲存在一個一維陣列中,請設計一個儘可能高效的演算法,找出A的主元素。若存在主元素,則輸出該元素;否則輸出-1該思想也可用於求陣列最長子序列(陣列資料包括負數和正數))

思想:

① 給出演算法的基本設計思想:演算法的策略是從前向後掃描陣列元繁,杯記出一個可能成為主元素的元素Num。然後重新計數,確認 Num是否是主元素。演算法可分為以下兩步:(摩爾投票法)

(1) 選取候選的主元素。依次掃描所給陣列中的每個整數,將第一個遇到的整數Num儲存到c中,記錄 Num 的出現次數為1;若遇到的下一個整數仍等於 Num,則計數加1,否則計數減1:當計數減到0時,將遇到的下一個整數儲存到c中,計數重新記為1,開始新一輪計數,即從當前位置開始重複上述過程,直到掃描完全部陣列元素

(2) 判斷c中元素是否是真正的主元素。再次掃描該陣列,統計c中元素出現的次數,若大於n/2,則為主元素:否則,序列中不存在主元素

8. 給定一個含n(n≥I)個整數的陣列,請攻訂一個杜時間一公馬)向效的演算法,找出陣列中未出現的最小正整數。例如,陣列{-5,3,2,3}中未出現的最小正整數是l;陣列{1,2,3}中未出現的最小正整數是4

思想:

① 要求在時間上儘可能高效,因此採用空問換時間的辦法。分配一個用於標記的陣列B[n]用來記錄A中是否出現了1~n中的正整數,B[0]對應正整數1,B[n-1]對應正整數n,初始化B中全部為0。由於A中含有n個整數,因此可能返回的值是 1n+1,當A中n個數恰好為1n 時返回n+1。當陣列A中出現了小於等於0或大於n的值時,會導致1~~n中出現空餘位置,返回結果必然在1~n中,因此對於A中出現了小於等於0或大於n的值,可以不採取任何操作

② 經過以上分析可以得出演算法流程:從A[0]開始遍歷A,若0<A[i]<=n.則令B[A[i]-1]=1;否則不做操作。對A遍歷結束後,開始遍歷陣列B,若能查詢到第一個滿足B[i]==0的下標i,返回i+1即為結果,此時說明A中未出現的最小正整數在1~n之間。若Bii]全部不為0,返回i+1(跳出迴圈時i=n,i+1等於n+1),此時說明A中未出現的最小正整數是n+1

9. 定義三元組(a, b,c)(a、b、c均為正數)的距離D=a-b+|b-c+Ic - a。給定3個非空整數集合S、S2和S,按升序分別儲存在3個陣列中。請設計一個儘可能高效的演算法,計算並輸出所有可能的三元組(a, b,c) (aES,bES, cES)中的最小距離。例如S={H1, 0, 9}, S={-25,-10, 10,11}SJ={2,9,17, 30, 41},則最小距離為2,相應的三元組為(9, 10, 9)

思想:

2)連結串列經典題目的程式設計思想

1. 設計一個遞迴演算法,刪除不帶頭結點的單連結串列L中所有值為×的結點

思想:

① 設f(L,x)的功能是刪除以工為首結點指標的單連結串列中所有值等於x的結點,顯然有f(L->next,x)的功能是刪除以L->next為首結點指標的單連結串列中所有值等於x的結點。由此,可以推出遞迴模型如下。

(1) 終止條件:f(L,x)=不做任何事情; 若L為空表

(2) 遞迴主體:f(L, x)=刪除*L結點;f(L->next, x); 若L->data==X

(3) :f(L,x)=f(L->next, x); 其他情況

2. 在帶頭結點的單連結串列L中,刪除所有值為×的結點,並釋放其空間假設值為×的結點不唯一,試編寫演算法以實現上述操作

思想:

① 採用尾插法建立單連結串列。用p指標掃描工的所有結點,當其值不為x時,將其連結到L之後,否則將其釋放

3. 試編寫演算法將帶頭結點的單連結串列就地逆置,所謂“就地”是指輔助空間複雜度為O(1)

思想:

① 將頭結點摘下,然後從第一結點開始,依次插入到頭結點的後面(頭插法建立單連結串列),直到最後一個結點為止,這樣就實現了連結串列的逆置

4. 給定兩個單連結串列,編寫演算法找出兩個連結串列的公共結點

思想:

① 先把問題簡化:如何判斷兩個單向連結串列有沒有公共結點?應注意到這樣:一個事實:若兩個連結串列有一個公共結點,則該公共結點之後的所有結點都是重合的,即它們的最後一個結點必然是重合的。因此,我們判斷兩個連結串列是不是有重合的部分時,只需要分別遍歷兩個連結串列到最後一個結點。若兩個尾結點是:一樣的,則說明它們有公共結點,否則兩個連結串列沒有公共結點。

② 然而,在上面的思路中,順序遍歷兩個連結串列到尾結點時,並不能保證在兩個連結串列上同時到達尾結點。這是因為兩個連結串列長度不一定一樣。但假設一個連結串列比另一個長k個結點,我們先在長的連結串列上遍歷k個結點,之後再同步遍歷,此時我們就能保證同時到達最後一個結點。由於兩個連結串列從第一個公共結點開始到連結串列的尾結點,這一部分是重合的,因此它們肯足也是同時到達第一公共結點的。於是在遍歷中,第一個相同的結點就是第一個公共的結點。

③ 根據這一思路中,我們先要分別遍歷兩個連結串列得到它們的長度,並求出兩個長度之差。在長的連結串列上先遍歷長度之差個結點之後,再同步遍歷兩個連結串列,直到找到相同的結點,或者一直到連結串列結束。此時,該方法的時間複雜度為 O(len1 + len2)

5. 已知兩個連結串列A和B分別表示兩個集合,其元素遞增排列。編制函式、求A與B的交集,並存放於A連結串列中

思想:

① 演算法思想:採用歸併的思想,設定兩個工作指標pa和pb,對兩個連結串列進行歸併掃描,只有同時出現在兩集合中的元素才連結到結果表中且僅保留一個,其他的結點全部釋放。當一個連結串列遍歷完畢後,釋放另一個表中剩下的全部結點(連結串列歸併型別的試題在各學校歷年真題中出現的頻率很高

6.

思想:

① 問題的關鍵是設計一個儘可能高效的演算法,通過連結串列的一次遍歷,找到倒數第k個結點的位置。演算法的基本設計思想是:定義兩個指標變盤p和q,初始時均指向頭結點的下一個結點(連結串列的第一個結點)p指標沿連結串列移動;當指標移動到第k個結點時,4指標開始與p指標同步移動;當指標移動到最後一個結點時,指標所指示結點為倒數第k個結點。以上過程對連結串列僅進行一遍掃描

7.

思想:

① 演算法的核心思想是用空間換時間。使用輔助陣列記錄連結串列中已出現的數值,從而只需對連結串列進行一趟掃描。因為|datal≤n,故輔助陣列q的大小為n+1,各元素的初值均為0。依次掃描連結串列中的各結點,同時檢查q[ldatal]的值,若為0則保留該結點,並令q[ldatal]=1;否則將該結點從連結串列中刪除

② 用雜湊表:設長度為n+1的陣列,每次插入一個元素因元素值與陣列下標相同故在陣列相應位置置為1,若檢測為1則刪除當前結點,反之為0插入且置為1

8. 設計一個演算法完成以下功能:判斷一個連結串列是否有環,如果有,找出環的入口點並返回,否則返回NULL

思想:

① (快慢指標也可作為求表長一半的方法)

9. 設線性表L=(a_1,a_2,…,a_(n-1),a_n)採用帶頭結點的單連結串列儲存,連結串列中的結點定義如下:

typedef struct node

{int data;

struct node*next;

}NODE;

請設計一個空間複雜度為O(1)且時間上儘可能高效的演算法,重新排列L中的各結點,得到線性表L'=(a_1,a_n,a_2,a_(n-1),a_3,a(n-2),…)

思想:

① 先觀察L=(a_1,a_2,…,a_(n-1),a_n)和L'=(a_1,a_n,a_2,a_(n-1),a_3,a(n-2),…),發現L'是由L摘取第一個元素,再摘取倒數第一個元素……依次合併而成的。為了方便連結串列後半段取元素,需要先將L後半段原地逆置[題目要求空間複雜度為O(1),不能借助棧],否則每取最後一個結點都需要遍歷一次連結串列

(1) 先找出連結串列L的中間結點,為此設定兩個指標p和q,指標p每次走一步,指標q每次走兩步,當指標q到達鏈尾時,指標p正好在連結串列的中間結點

(2) 然後將L的後半段結點原地逆置

(3) 從單連結串列前後兩段中依次各取一個結點

相關文章