2.3线性表的链式表示和实现
算法2.8:單鏈表中插入一個節(jié)點
下面是書中的偽代碼:
Status ListInsert_L(LinkList &L, int i, ElemType e) { // 在帶頭結(jié)點的單鏈線性表L的第i個元素之前插入元素eLinkList p,s;p = L; int j = 0;while (p && j < i-1) { // 尋找第i-1個結(jié)點p = p->next;++j;} if (!p || j > i-1) return ERROR; // i小于1或者大于表長s = (LinkList)malloc(sizeof(LNode)); // 生成新結(jié)點s->data = e; s->next = p->next; // 插入L中p->next = s;return OK; } // LinstInsert_L下面我們來分析下:
1.第一行是Status表示一種狀態(tài),因為C語言里面沒有泛型,所以用這個表示。
2.這里的LinkList是*LinkList(書上對這個有定義,在本博客中不再說明)。
3.這里如果LinkList &L,是一個鏈表,這個p指向了L的地址。這樣的話當(dāng)while循環(huán)結(jié)束后,那么p就是指向第i-1個元素的地址。
4.s在堆中開辟了一個LNode大小的空間,并且把e賦值給了s->data。
5.插入時我們要注意,先把p->next給s->next(就是先連s后繼,如果先連接p的后繼話這個鏈表是不能連起來的,大家可以試試),然后在連接p的后繼。
算法2.9:帶頭結(jié)點的鏈表的刪除
下面是書中的偽代碼:
Status ListDelete_L(LinkList &L, int i, ElemType &e) { // 在帶頭結(jié)點的單鏈線性表L中,刪除第i個元素,并由e返回其值LinkList p,q;p = L;int j = 0;while (p->next && j < i-1) { // 尋找第i個結(jié)點,并令p指向其前趨p = p->next;++j;}if (!(p->next) || j > i-1) return ERROR; // 刪除位置不合理q = p->next;p->next = q->next; // 刪除并釋放結(jié)點e = q->data;free(q);return OK; } // ListDelete_L 下面是思路:這個程序比較簡單,我們講解下思路就可以了。先用p指向要刪除的LinkList的前面那個元素,用q指向p后面那個元素(也就是要刪除的元素),把q->next賦值各p->next,這樣的化就把q隔離出來了,最后在free就可以了。這個比較簡單。
算法2.10:創(chuàng)建帶頭結(jié)點的單鏈表。
下面是書中的偽代碼:
void CreateList_L(LinkList &L, int n) { // 逆位序輸入(隨機(jī)產(chǎn)生)n個元素的值,建立帶表頭結(jié)點的單鏈線性表L LinkList p;int i;L = (LinkList)malloc(sizeof(LNode));L->next = NULL; // 先建立一個帶頭結(jié)點的單鏈表for (i=n; i>0; --i) {p = (LinkList)malloc(sizeof(LNode)); // 生成新結(jié)點p->data = random(200); // 改為一個隨機(jī)生成的數(shù)字(200以內(nèi))p->next = L->next; L->next = p; // 插入到表頭} } // CreateList_L下面是思路:
1.帶頭結(jié)點的鏈表是指,鏈表里面的第一個結(jié)點,不存數(shù)據(jù)。
2.這里的i是要包含除頭結(jié)點外的還有多少個節(jié)點。
3.這里的random函數(shù)是產(chǎn)生隨機(jī)種子,他在頭文件#include<stdlib.h>中,大小為0~199。
4這里是在表頭中不停的插入,而不是在表尾中插入。
算法2.11:
如何將兩個有序鏈表并為一個有序鏈表。
下面是偽代碼:
void MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc) {// 已知單鏈線性表La和Lb的元素按值非遞減排列。// 歸并La和Lb得到新的單鏈線性表Lc,Lc的元素也按值非遞減排列。LinkList pa, pb, pc;pa = La->next; pb = Lb->next;Lc = pc = La; // 用La的頭結(jié)點作為Lc的頭結(jié)點while (pa && pb) {if (pa->data <= pb->data) {pc->next = pa; pc = pa; pa = pa->next;}else { pc->next = pb; pc = pb; pb = pb->next; }}pc->next = pa ? pa : pb; // 插入剩余段free(Lb); // 釋放Lb的頭結(jié)點 } // MergeList_L下面我們來分析下:
1.這個程序是思路是,用三個LinkList,pa,pb.pc分別指向La,Lb的第一個元素Lc的頭結(jié)點,然后比較,pa->data,和pb->data的值,誰下就把誰放入pc,然后指針后移,在最后,把還剩下的那個鏈的部分,直接接到pc。
2.這偽代碼有個問題,也就是最后的free(Lb),如果要清理,也要加上free(La)才行。
3.這個例子的巧妙之處在于只需將原來兩個鏈表中節(jié)點之間的關(guān)系解除,程序按元素非遞減的關(guān)系將所有節(jié)點鏈接成一個鏈表即可。
算法2.12:
在靜態(tài)鏈線性表L中查找第1個值為e的元素
下面是偽代碼:
int LocateElem_SL(SLinkList S, ElemType e) { // 在靜態(tài)單鏈線性表L中查找第1個值為e的元素。// 若找到,則返回它在L中的位序,否則返回0。int i;i = S[0].cur; // i指示表中第一個結(jié)點while (i && S[i].data != e) i = S[i].cur; // 在表中順鏈查找return i; } // LocateElem_SL 下面我們來分析下:1.靜態(tài)鏈表:在不設(shè)置“指針”類型的高級程序設(shè)計語言中使用的,需要預(yù)先分配一個較大的空間。
2.這個程序的思路是:cur是一個指示器類似于next,如下圖所示,相信看了下圖,就能理解,下圖是插入數(shù)據(jù)元素SHI和刪除數(shù)據(jù)元素ZHENG
3.這個cur存的是下標(biāo)(因為這是SLinkList[MAXSIZE])。
4.最后返回數(shù)組下標(biāo)的值。
算法2.13:
在靜態(tài)鏈中將所有未被使用過以及被刪除的分量用游標(biāo)鏈成一個備用的鏈表,每當(dāng)進(jìn)行插入時便可從備用鏈表上取得第一個結(jié)點作為待插入點;反之,在刪除時將此元素插入S表
下面以(A-B)U(B-A)=(AUB)-(A∩B)為例子。
假設(shè)由終端輸入集合元素,先建立表示集合A的靜態(tài)鏈表S,從而在輸入集合B的元素的同時查找S表,若存在和B相同的元素,則從S表刪除,否則插入S表。
算法2.13功能:將整個數(shù)組空間初始化成一個鏈表。
算法2.14功能:從備用空間取得一個結(jié)點。
算法2.15功能:將空間節(jié)點鏈結(jié)到備用鏈表上。
算法2.16功能:完整功能實現(xiàn)
下面是偽代碼:
void InitSpace_SL(SLinkList space) {// 將一維數(shù)組space中各分量鏈成一個備用鏈表,space[0].cur為頭指針,// "0"表示空指針for (int i=0; i<MAXSIZE-1; ++i) space[i].cur = i+1;space[MAXSIZE-1].cur = 0; } // InitSpace_SL 下面來分析下:1.init的全寫為initialization,意思為初始化。
2.這個程序的最后是space[MAXSIZE-1].cur=0;是把這個靜態(tài)鏈頭尾相連變成一個環(huán)。
下面是代碼:
int Malloc_SL(SLinkList &space) { // 若備用空間鏈表非空,則返回分配的結(jié)點下標(biāo),否則返回0int i = space[0].cur;if (space[0].cur) space[0].cur = space[space[0].cur].cur;return i; } // Malloc_SL 下面我們來分析下代碼:1.malloc的全稱為mallocate,意思是分配。
2.這個程序是首先得到下標(biāo)為0的鏈表對應(yīng)的cur,當(dāng)下標(biāo)為0的cur不為0時,說明非空,則把space[0].cur這個是數(shù)提出來,再把這個數(shù)組對應(yīng)的下標(biāo)賦值給0對應(yīng)的下標(biāo)。
3.不懂的同學(xué),帶幾個數(shù)進(jìn)去就懂了。
下面是偽代碼:
void Free_SL(SLinkList &space, int k) {// 將下標(biāo)為k的空閑結(jié)點回收到備用鏈表space[k].cur = space[0].cur; space[0].cur = k; } // Free_SL 下面我們來分析下:這個是先把以前0的下標(biāo)給后數(shù)組第k行對應(yīng)的下標(biāo),然后到數(shù)組0下標(biāo)改為k。
算法2.16:完整功能實現(xiàn)
下面是偽代碼:
void difference(SLinkList &space, int &S) {// 依次輸入集合A和B的元素,在一維數(shù)組space中建立表示集合(A-B)∪(B-A)// 的靜態(tài)鏈表, S為頭指針。假設(shè)備用空間足夠大,space[0].cur為頭指針。int i, j, k, m, n, p, r;ElemType b;InitSpace_SL(space); // 初始化備用空間S = Malloc_SL(space); // 生成S的頭結(jié)點r = S; // r指向S的當(dāng)前最后結(jié)點m = random(2,8); // 輸入A的元素個數(shù)n = random(2,8); // 輸入B的元素個數(shù)printf(" A = ( ");initrandom_c1();for (j=1; j<=m; ++j) { // 建立集合A的鏈表i = Malloc_SL(space); // 分配結(jié)點//printf("i=%d ",i);space[i].data = random_next_c1(); // 輸入A的元素值printf("%c ", space[i].data); // 輸出A的元素space[r].cur = i; r = i; // 插入到表尾}printf(")\n");space[r].cur = 0; // 尾結(jié)點的指針為空initrandom_c1();printf(" B = ( ");for (j=1; j<=n; ++j) {// 依次輸入B的元素,若不在當(dāng)前表中,則插入,否則刪除b = random_next_c1(); // 輸入B的元素值printf("%c ", b); // 輸出B的元素p = S; k = space[S].cur; // k指向集合A中第一個結(jié)點while (k!=space[r].cur && space[k].data!=b) {// 在當(dāng)前表中查找p = k; k = space[k].cur;}if (k == space[r].cur) {// 當(dāng)前表中不存在該元素,插入在r所指結(jié)點之后,且r的位置不變i = Malloc_SL(space);space[i].data = b;space[i].cur = space[r].cur;space[r].cur = i;} else { // 該元素已在表中,刪除之space[p].cur = space[k].cur;Free_SL(space, k);if (r == k) r = p; // 若刪除的是尾元素,則需修改尾指針}}printf(")\n"); } // difference下面我們來分析一下:
1.這里面用產(chǎn)生了兩個隨機(jī)種子賦值給了m和n。
2.這里的random_next_c1();函數(shù)估計就是參數(shù)一個隨機(jī)字符。
3.第一個for循環(huán)結(jié)束后把space里面下標(biāo)為1-m的數(shù)都賦值了。
4.第二個for循環(huán)里面的while循環(huán),是判斷是否有相同的數(shù),和是不是檢索完了數(shù)組。
假設(shè)A=(c,b,e,g,f,d),B=(a,b,n,f)則,這圖很好的表示了此算法:
總結(jié)
以上是生活随笔為你收集整理的2.3线性表的链式表示和实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/C++如何连接MySQL服务器以及简
- 下一篇: Qt creator5.7 OpenCV