【資料結構】線性表的單鏈表儲存結構表示和實現
阿新 • • 發佈:2019-02-03
資料結構 線性表的單鏈表儲存結構表示和實現
參考程式碼如下:
執行結果如下:/* 名稱:線性表的單鏈表儲存結構表示和實現 編譯環境:VC++6.0 日期: 2014-3-27 */ #include <stdio.h> #include <malloc.h> #include <stdlib.h> typedef int ElemType; // 線性表的單鏈表儲存結構 typedef struct LNode { ElemType data; //資料域 struct LNode *next; //指標域 }LNode, *LinkList; // typedef struct LNode *LinkList; // 另一種定義LinkList的方法 // 構造一個空的線性表L int InitList(LinkList *L) { /* 產生頭結點L,並使L指向此頭結點,頭節點的資料域為空,不放資料的。 void * malloc(size_t) 這裡對返回值進行強制型別轉換了,返回值是指向空型別的指標型別。 */ (*L) = (LinkList)malloc( sizeof(struct LNode) ); if( !(*L) ) exit(0); // 儲存分配失敗 (*L)->next = NULL; // 指標域為空 return 1; } // 銷燬線性表L,將包括頭結點在內的所有元素釋放其儲存空間。 int DestroyList(LinkList *L) { LinkList q; // 由於單鏈表的每一個元素是單獨分配的,所以要一個一個的進行釋放 while( *L ) { q = (*L)->next; free( *L ); //釋放 *L = q; } return 1; } /* 將L重置為空表,即將連結串列中除頭結點外的所有元素釋放其存 儲空間,但是將頭結點指標域置空,這和銷燬有區別哦。不改變L,所以 不需要用指標。 */ int ClearList( LinkList L ) { LinkList p, q; p = L->next; // p指向第一個結點 while( p ) // 沒到表尾則繼續迴圈 { q = p->next; free( p ); //釋放空間 p = q; } L->next = NULL; // 頭結點指標域為空,連結串列成了一個空表 return 1; } // 若L為空表(根據頭結點L->next來判斷,為空則是空表),則返回1, // 否則返回0。 int ListEmpty(LinkList L) { if( L->next ) // 非空 return 0; else return 1; } // 返回L中資料元素個數。 int ListLength(LinkList L) { int i = 0; LinkList p = L->next; // p指向第一個結點 while(p) // 沒到表尾,則繼續迴圈 { i++; p=p->next; } return i; } // L為帶頭結點的單鏈表的頭指標。當第i個元素存在時,其值賦給e並 // 返回1,否則返回0。 int GetElem(LinkList L,int i,ElemType *e) { int j = 1; // j為計數器 LinkList p=L->next; // p指向第一個結點 while(p&&j<i) // 順指標向後查詢,直到p指向第i個元素或p為空 { p=p->next; j++; } if(!p||j>i) // 第i個元素不存在 return 0; *e = p->data; // 取第i個元素 return 1; } // 返回L中第1個與e滿足關係compare()的資料元素的位序。 // 若這樣的資料元素不存在,則返回值為0 int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType)) { int i=0; LinkList p=L->next; while(p) //將連結串列的每一個元素進行對比 { i++; if(compare(p->data,e)) // 找到這樣的資料元素 return i; p=p->next; } return 0; } // 若cur_e是L的資料元素,且不是第一個,則用pre_e返回它的前驅, // 返回1;否則操作失敗,pre_e無定義,返回-1 int PriorElem(LinkList L,ElemType cur_e,ElemType *pre_e) { LinkList q, p=L->next; // p指向第一個結點 while(p->next) // p所指結點有後繼 { q=p->next; // q為p的後繼 if(q->data==cur_e) { *pre_e=p->data; return 1; } p=q; // p向後移 } return -1; } // 若cur_e是L的資料元素,且不是最後一個,則用next_e返回它的後繼, // 返回1;否則操作失敗,next_e無定義,返回-1 int NextElem(LinkList L,ElemType cur_e,ElemType *next_e) { LinkList p=L->next; // p指向第一個結點 while(p->next) // p所指結點有後繼 { if(p->data==cur_e) { *next_e=p->next->data; return 1; } p=p->next; } return -1; } // 在帶頭結點的單鏈線性表L中第i個位置之前插入元素e int ListInsert(LinkList *L,int i,ElemType e) { int j=0; LinkList p=*L,s; while(p && j<i-1) // 尋找第i-1個結點 { p=p->next; j++; } if(!p || j>i-1) // i小於1或者大於表長 return 0; s=(LinkList)malloc(sizeof(struct LNode)); // 生成新結點 s->data=e; // 插入L中 s->next=p->next; p->next=s; return 1; } // 在帶頭結點的單鏈線性表L中,刪除第i個元素,並由e返回其值 int ListDelete(LinkList *L, int i,ElemType *e) { int j = 0; LinkList p=*L,q; while(p->next&&j<i-1) // 尋找第i個結點,並令p指向其前趨 { p=p->next; j++; } if(!p->next||j>i-1) // 刪除位置不合理 return 0; q=p->next; // 刪除並釋放結點 p->next=q->next; *e=q->data; free(q); return 1; } // 依次對L的每個資料元素呼叫函式vi() int ListTraverse(LinkList L,void(*vi)(ElemType)) { LinkList p=L->next; //對所有元素呼叫函式vi while(p) { vi(p->data); p=p->next; } printf("\n"); return 1; } // 在按非降序排列的線性表L中按非降序插入新的資料元素e void InsertAscend(LinkList L,ElemType e) { LinkList q=L, p=L->next; while(p&&e>p->data) { q=p; p=p->next; } q->next=(LinkList)malloc(sizeof(struct LNode)); // e插在q後 q->next->data=e; q->next->next=p; } // 按非升序排列的線性表L中按非升序插入新的資料元素e void InsertDescend(LinkList L,ElemType e) { LinkList q=L,p=L->next; while(p&&e<p->data) { q=p; p=p->next; } q->next=(LinkList)malloc(sizeof(struct LNode)); // e插在q後 q->next->data=e; q->next->next=p; } // L的頭部插入新的資料元素e,作為連結串列的第一個元素 int HeadInsert(LinkList L,ElemType e) { LinkList s; s=(LinkList)malloc(sizeof(struct LNode)); // 生成新結點 s->data=e; // 給結點賦值 s->next=L->next; // 插在表頭 L->next=s; return 1; } // 在L的尾部插入新的資料元素e,作為連結串列的最後一個元素 int EndInsert(LinkList L,ElemType e) { LinkList p=L; while(p->next) // 使p指向表尾元素 p=p->next; p->next=(LinkList)malloc(sizeof(struct LNode)); // 在表尾生成新結點 p->next->data=e; // 給新結點賦值 p->next->next=NULL; // 表尾 return 1; } // 刪除L的第一個資料元素,並由e返回其值 int DeleteFirst(LinkList L,ElemType *e) { LinkList p=L->next; if(p) { *e=p->data; L->next=p->next; free(p); return 1; } else return 0; } // 刪除L的最後一個數據元素,並用e返回其值 int DeleteTail(LinkList L,ElemType *e) { LinkList p=L,q; if(!p->next) // 連結串列為空 return 0; while(p->next) { q=p; p=p->next; } q->next=NULL; // 新尾結點的next域設為NULL *e=p->data; free(p); return 1; } // 刪除表中值為e的元素,並返回1;如無此元素,則返回0 int DeleteElem(LinkList L,ElemType e) { LinkList p=L,q; while(p) { q=p->next; if(q&&q->data==e) { p->next=q->next; free(q); return 1; } p=q; } return 0; } // 用e取代表L中第i個元素的值 int ReplaceElem(LinkList L,int i,ElemType e) { LinkList p=L; int j=0; //找到第i個元素的位置給p while(p->next && j<i) { j++; p=p->next; } if(j==i) { p->data=e; return 1; } else // 表中不存在第i個元素 return 0; } // 按非降序建立n個元素的線性表 int CreatAscend(LinkList *L,int n) { int j; LinkList p,q,s; if(n<=0) return 0; InitList(L); printf("請輸入%d個元素:(空格)\n",n); s=(LinkList)malloc(sizeof(struct LNode)); // 第一個結點 scanf("%d",&s->data); s->next=NULL; (*L)->next=s; for(j=1;j<n;j++) { s=(LinkList)malloc(sizeof(struct LNode)); // 其餘結點 scanf("%d",&s->data); q=*L; p=(*L)->next; while(p&&p->data<s->data) // p沒到表尾,且所指元素值小於新值 { q=p; p=p->next; // 指標後移 } s->next=q->next; // 元素插在q的後面 q->next=s; } return 1; } // 按非升序建立n個元素的線性表 int CreatDescend(LinkList *L,int n) { int j; LinkList p,q,s; if(n<=0) return 0; InitList(L); printf("請輸入%d個元素:(空格)\n",n); s=(LinkList)malloc(sizeof(struct LNode)); // 第一個結點 scanf("%d",&s->data); s->next=NULL; (*L)->next=s; for(j=1;j<n;j++) { s=(LinkList)malloc(sizeof(struct LNode)); // 其餘結點 scanf("%d",&s->data); q=*L; p=(*L)->next; while(p&&p->data>s->data) // p沒到表尾,且所指元素值大於新值 { q=p; p=p->next; // 指標後移 } s->next=q->next; // 元素插在q的後面 q->next=s; } return 1; } // 返回表頭元素的值 int GetFirstElem(LinkList L,ElemType *e) { LinkList p=L->next; //第一個結點給p if(!p) // 空表 return 0; else // 非空表 *e=p->data; return 1; } // 逆位序(插在表頭)輸入n個元素的值,建立帶表頭結構的單鏈線性表L void CreateList(LinkList *L,int n) { int i; LinkList p; // 先建立一個帶頭結點的空單鏈表,相當於初始化單鏈表 *L=(LinkList)malloc(sizeof(struct LNode)); (*L)->next=NULL; printf("請輸入%d個數據\n",n); for(i=n;i>0;--i) { p=(LinkList)malloc(sizeof(struct LNode)); // 生成新結點 scanf("%d",&p->data); // 輸入元素值 p->next=(*L)->next; // 插入到表頭 (*L)->next=p; } } // 正位序(插在表尾)輸入n個元素的值,建立帶表頭結構的單鏈線性表 void CreateList2(LinkList *L,int n) { int i; LinkList p,q; // 先建立一個帶頭結點的空單鏈表,相當於初始化單鏈表 *L=(LinkList)malloc(sizeof(struct LNode)); // 生成頭結點 (*L)->next=NULL; q=*L; printf("請輸入%d個數據\n",n); for(i=1;i<=n;i++) { p=(LinkList)malloc(sizeof(struct LNode)); scanf("%d",&p->data); q->next=p; q=q->next; } p->next=NULL; } // 已知單鏈線性表La和Lb的元素按值非遞減排列。 // 歸併La和Lb得到新的單鏈線性表Lc,Lc的元素也按值非遞減排列 void MergeList(LinkList La,LinkList *Lb,LinkList *Lc) { LinkList pa=La->next,pb=(*Lb)->next,pc; *Lc=pc=La; // 用La的頭結點作為Lc的頭結點 while(pa&&pb) { if(pa->data <= pb->data) { pc->next=pa; *Lc=pa; pa=pa->next; } else { pc->next=pb; pc=pb; pb=pb->next; } } pc->next=pa ? pa : pb; // 插入剩餘段 free(*Lb); // 釋放Lb的頭結點 Lb=NULL; } // 判斷是否相等的函式,Union()用到 int equal(ElemType c1,ElemType c2) { if(c1==c2) return 1; else return 0; } // 將所有線上性表Lb中但不在La中的資料元素插入到La中 void Union(LinkList La,LinkList Lb) { ElemType e; int La_len,Lb_len; int i; La_len=ListLength(La); // 求線性表的長度 Lb_len=ListLength(Lb); for(i=1;i<=Lb_len;i++) { GetElem(Lb,i,&e); // 取Lb中第i個數據元素賦給e if(!LocateElem(La,e,equal)) // La中不存在和e相同的元素,則插入之 ListInsert(&La,++La_len,e); } } // 資料元素判定函式(相等為1,否則為0) int comp(ElemType c1,ElemType c2) { if(c1==c2) return 1; else return 0; } void visit(ElemType c) { printf("%d ",c); } int main() { LinkList L, La, Lb, Lc; ElemType e, e0, d; int i, j, n, k; //初始化一個單鏈表 i=InitList(&L); //通過插入操作建立一個單鏈表 for(j=1;j<=5;j++) i=ListInsert(&L,1,j); //呼叫visit函式,對單鏈表進行遍歷 printf("在L的表頭依次插入1~5後:L="); ListTraverse(L,visit); // 依次對元素呼叫visit(),輸出元素的值 //判斷單鏈表是否為空 i=ListEmpty(L); printf("L是否空:i=%d(1:是 0:否)\n",i); //清空單鏈表 i=ClearList(L); printf("清空L後:L="); ListTraverse(L,visit); //判斷單鏈表是否為空 i=ListEmpty(L); printf("L是否空:i=%d(1:是 0:否)\n",i); //再次通過插入操作建立一個單鏈表 for(j=1;j<=10;j++) ListInsert(&L,j,j); printf("在L的表尾依次插入1~10後:L="); ListTraverse(L,visit); //取得單鏈表的第5個元素 GetElem(L,5,&e); printf("第5個元素的值為:%d\n",e); //在單鏈表中找到和j滿足comp函式關係的元素 for(j=0;j<=1;j++) { k=LocateElem(L,j,comp); if(k) printf("第%d個元素的值為%d\n",k,j); else printf("沒有值為%d的元素\n",j); } //找到某個元素的前驅 for(j=1;j<=2;j++) // 測試頭兩個資料 { GetElem(L,j,&e0); // 把第j個數據賦給e0 i=PriorElem(L,e0,&e); // 求e0的前驅 if(i==-1) printf("元素%d無前驅\n",e0); else printf("元素%d的前驅為:%d\n",e0,e); } //找到某個元素的後繼 for(j=ListLength(L)-1;j<=ListLength(L);j++)// 測試最後兩個資料 { GetElem(L,j,&e0); // 把第j個數據賦給e0 i=NextElem(L,e0,&e); // 求e0的後繼 if(i==-1) printf("元素%d無後繼\n",e0); else printf("元素%d的後繼為:%d\n",e0,e); } //求單鏈表的表長 k=ListLength(L); // k為表長 //刪除操作 for(j=k+1;j>=k;j--) { i=ListDelete(&L,j,&e); // 刪除第j個數據 if(i==0) printf("刪除第%d個數據失敗\n",j); else printf("刪除的元素為:%d\n",e); } printf("依次輸出L的元素:"); ListTraverse(L,visit); //銷燬單鏈表 DestroyList(&L); printf("銷燬L後:L=%u\n\n",L); printf("按非降序建立n個元素的線性表L,請輸入元素個數n: "); scanf("%d",&n); CreatAscend(&L,n); printf("依次輸出L的元素:"); ListTraverse(L,visit); // 按非降序插入元素10 InsertAscend(L,10); printf("按非降序插入元素10後,線性表L為:"); ListTraverse(L,visit); // 在L的頭部插入12 HeadInsert(L,12); // 在L的尾部插入9 EndInsert(L,9); printf("在L的頭部插入12,尾部插入9後,線性表L為:"); ListTraverse(L,visit); i=GetFirstElem(L,&e); printf("第1個元素是: %d\n",e); printf("請輸入要刪除的元素的值: "); scanf("%d",&e); i=DeleteElem(L,e); if(i) printf("成功刪除%d!\n",e); else printf("不存在元素%d!\n",e); printf("線性表L為:"); ListTraverse(L,visit); printf("請輸入要取代的元素的序號 元素的新值: "); scanf("%d%d",&n,&e); ReplaceElem(L,n,e); printf("線性表L為:"); ListTraverse(L,visit); DestroyList(&L); printf("銷燬L後,按非升序重新建立n個元素的線性表L,請輸入" "元素個數n(>2): "); scanf("%d",&n); CreatDescend(&L,n); printf("依次輸出L的元素:"); ListTraverse(L,visit); // 按非升序插入元素10 InsertDescend(L,10); printf("按非升序插入元素10後,線性表L為:"); ListTraverse(L,visit); printf("請輸入要刪除的元素的值: "); scanf("%d",&e); i=DeleteElem(L,e); if(i) printf("成功刪除%d!\n",e); else printf("不存在元素%d!\n",e); printf("線性表L為:"); ListTraverse(L,visit); DeleteFirst(L,&e); DeleteTail(L,&d); printf("刪除表頭元素%d和表尾元素%d後,線性表L為:",e,d); ListTraverse(L,visit); printf("\n"); // 測試演算法2.11 n = 3; CreateList2(&La,n); // 正位序輸入n個元素的值 printf("正位建立後La="); // 輸出連結串列La的內容 ListTraverse(La,visit); CreateList(&Lb,n); // 逆位序輸入n個元素的值 printf("逆位建立後Lb="); // 輸出連結串列Lb的內容 ListTraverse(Lb,visit); DestroyList(&La); DestroyList(&Lb); // 測試演算法2.12 //初始化一個單鏈表La i=InitList(&La); //通過插入操作建立一個單鏈表 for(j=2;j<=10;j+=2) i=ListInsert(&La,1,j); printf("La="); // 輸出連結串列La的內容 ListTraverse(La,visit); //初始化一個單鏈表 i=InitList(&Lb); //通過插入操作建立一個單鏈表 for(j=1;j<=10;j+=2) i=ListInsert(&Lb,1,j); printf("Lb="); // 輸出連結串列Lb的內容 ListTraverse(Lb,visit); // 按非遞減順序歸併La和Lb,得到新表Lc MergeList(La,&Lb,&Lc); printf("合併La和Lb後,Lc = "); // 輸出連結串列Lc的內容 ListTraverse(Lc,visit); // 測試演算法2.1 i=InitList(&La); if(i==1) // 建立空表La成功 for(j=1;j<=5;j++) // 在表La中插入5個元素 i=ListInsert(&La,j,j); printf("La= "); // 輸出表La的內容 ListTraverse(La,visit); InitList(&Lb); // 也可不判斷是否建立成功 for(j=1;j<=5;j++) // 在表Lb中插入5個元素 i=ListInsert(&Lb,j,2*j); printf("Lb= "); // 輸出表Lb的內容 ListTraverse(Lb,visit); Union(La,Lb); printf("new La= "); // 輸出新表La的內容 ListTraverse(La,visit); system("pause"); return 0; } /* 輸出效果: 在L的表頭依次插入1~5後:L=5 4 3 2 1 L是否空:i=0(1:是 0:否) 清空L後:L= L是否空:i=1(1:是 0:否) 在L的表尾依次插入1~10後:L=1 2 3 4 5 6 7 8 9 10 第5個元素的值為:5 沒有值為0的元素 第1個元素的值為1 元素1無前驅 元素2的前驅為:1 元素9的後繼為:10 元素10無後繼 刪除第11個數據失敗 刪除的元素為:10 依次輸出L的元素:1 2 3 4 5 6 7 8 9 銷燬L後:L=0 按非降序建立n個元素的線性表L,請輸入元素個數n: 3 請輸入3個元素:(空格) 1 3 2 依次輸出L的元素:1 2 3 按非降序插入元素10後,線性表L為:1 2 3 10 在L的頭部插入12,尾部插入9後,線性表L為:12 1 2 3 10 9 第1個元素是: 12 請輸入要刪除的元素的值: 1 成功刪除1! 線性表L為:12 2 3 10 9 請輸入要取代的元素的序號 元素的新值: 3 4 線性表L為:12 2 4 10 9 銷燬L後,按非升序重新建立n個元素的線性表L,請輸入元素個數n(>2): 3 請輸入3個元素:(空格) 1 3 2 依次輸出L的元素:3 2 1 按非升序插入元素10後,線性表L為:10 3 2 1 請輸入要刪除的元素的值: 3 成功刪除3! 線性表L為:10 2 1 刪除表頭元素10和表尾元素1後,線性表L為:2 請輸入3個數據 1 3 2 正位建立後La=1 3 2 請輸入3個數據 1 3 2 逆位建立後Lb=2 3 1 La=10 8 6 4 2 Lb=9 7 5 3 1 合併La和Lb後,Lc = 9 7 5 3 1 10 8 6 4 2 La= 1 2 3 4 5 Lb= 2 4 6 8 10 new La= 1 2 3 4 5 6 8 10 請按任意鍵繼續. . . */