資料結構(c語言版)中線性表的單鏈表儲存結構
阿新 • • 發佈:2018-11-19
本文轉自:https://blog.csdn.net/prlhnxx/article/details/79174782
/* run this program using the console pauser or add your own getch, system("pause") or input loop */ //用到的庫檔案 #include <stdio.h> //printf() ;scanf() #include <stdlib.h> //exit() #include <malloc.h> //malloc() #include <time.h> //srand((unsigned)time(NULL)) ; //函式結果狀態程式碼 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 //Status是函式的型別,其值是函式結果狀態程式碼 typedef int Status ; //#define ElemType int //也可以用巨集定義確定ElemType型別 typedef int ElemType ; //-----線性表的單鏈表儲存結構----- typedef struct LNode { //自定義資料型別 ElemType data ; //資料域 struct LNode *next ; //指標域 } LNode, *LinkList ; // 操作結果:構造一個空的線性表L。 Status InitList_L(LinkList &L) { L = (LinkList)malloc(sizeof(LNode)) ; if(!L) { //儲存分配失敗 printf("初始化失敗") ; exit(OVERFLOW) ; //exit(-1)程式異常退出 } L->next = NULL ; // 先建立一個帶頭結點的單鏈表,並使頭結點的指標域為NULL return OK ; }// InitList_L // 初始條件:線性表L已存在。 // 操作結果:銷燬線性表L。 Status DestroyList_L(LinkList &L) { free(L) ; //釋放線性表頭結點指標域 return OK ; }// DestroyList_L // 初始條件:線性表L已存在。 // 操作結果:將L重置為空表。 Status ClearList_L(LinkList &L) { LinkList p = L->next, ptmp ; //p指向線性表頭結點 while(p) { //釋放每個結點的指標域 ptmp = p->next ; free(p) ; p = ptmp ; } L->next = NULL ; //頭結點指標域為空 return OK ; }// ClearList_L // 初始條件:線性表L已存在。 // 操作結果:若L為空表,返回TRUE,否則返回FALSE Status ListEmpty_L(LinkList L) { return L->next ? FALSE : TRUE ; }// ListEmpty_L // 初始條件:線性表L已存在。 // 操作結果:返回L中資料元素個數。 int ListLength_L(LinkList L) { int nElem = 0 ; LinkList p = L->next ; //p指向第一個結點 while(p) { nElem ++ ; p = p->next ; } return nElem ; }// ListLength // 初始條件:線性表L已存在,1≤i≤ListLength(L) 。 // 操作結果:用e返回L中第i個數據元素的值。 Status GetElem_L(LinkList L, int i, ElemType &e) { LinkList p = L->next ; //初始化,p指向第一個結點 int j = 1 ; //j為計數器 while ( p && j<i ) { //順指標向後查詢,直到p指向第i個元素或p為空 p = p->next ; ++ j ; } if ( !p || j>i ) return ERROR ; //第i個元素不存在 e = p->data ; //取第i個元素 return OK ; }// GetElem_L 演算法2.8 // 初始條件:線性表L已存在,compare()是資料元素判定函式。 // 操作結果:返回L中第1個與e滿足compare()的資料元素的位序,若這樣的資料元素不存在,則返回值為0。 Status compare(ElemType listElem, ElemType e) { return listElem == e ? TRUE : FALSE ; }// Compare int LocateElem_L(LinkList L, ElemType e, Status (*pfn_compare)(ElemType, ElemType)) { int pos = 1 ; LinkList p = L->next ; //p指向連結串列第1個元素 while(p && !(*pfn_compare)(p->data, e)) { ++ pos ; p = p->next ; //指標後移 p->next = NULL時 意味著找到表尾元素了 } if(pos<=ListLength_L(L)) //pos的值線上性表中,返回元素的位序 return pos ; else return 0 ; }// LocateElem_L // 初始條件:線性表L已存在。 // 操作結果:若cur_e是L的資料元素,且不是第一個,則用pre_e返回它的前驅,否則操作失敗,pre_e無定義。 Status PriorElem_L(LinkList L, ElemType cur_e, ElemType &pre_e) { int i = LocateElem_L(L, cur_e, compare) ; if(i==0 || i==1) return ERROR ; GetElem_L(L, i-1, pre_e) ; return OK ; }// PriorElem_L // 初始條件:線性表L已存在。 // 操作結果:若cur_e是L的資料元素,且不是最後一個,則用next_e返回它的後繼,否則操作失敗,pre_e無定義。 Status NextElem_Sq(LinkList L, ElemType cur_e, ElemType &next_e) { int i = LocateElem_L(L, cur_e, compare) ; if(i==0 || i==ListLength_L(L)) return ERROR ; GetElem_L(L, i+1, next_e) ; return OK ; }// NextElem_Sq // 初始條件:線性表L已存在,1≤pos≤ListLength(L)+1。 // 操作結果:在L中第pos個位置之前插入新的元素e,L的長度加1。 Status ListInsert_L(LinkList &L, int pos, ElemType e) { LinkList p = L ; //定義一個結構體指標變數p,指向線性表起始位置(頭結點)L。 int j = 0 ; while (p && j<pos-1) { //尋找第i-1個結點,並令p指向其前趨。 p = p->next ; //p非空,且j<i-1,說明指標位於線性表內 ++j ; } if (!p || j>pos-1) //插入位置是否合法(第i個結點存在,插入的位置在表內) return ERROR ; LinkList s = (LinkList) malloc(sizeof(LNode)) ;// 生成新結點 s->data = e ; // 將插入的元素值賦給 新生成結點的資料域 s->next = p->next ; // 新生成結點的指標域 指向下一個結點 (即將結點i-1中指向第i個元素的指標域p->next,賦給新結點的指標域s->next) p->next = s ; // 結點i-1的指標域 指向新生成的結點(即將指向新生成結點的指標s,賦給第i-1個元素的指標域p->next) printf("插入的元素:%d, 插入的位置:%d\n", e, pos) ; return OK ; }// ListInsert_L 演算法2.9 // 初始條件:線性表L已存在且非空,1≤pos≤ListLength(L)。 // 操作結果:刪除L的第pos個數據元素,並用e返回其值,L的長度減1。 Status ListDelete_L(LinkList &L, int pos, ElemType &e) { LinkList p = L ; //定義一個結構體指標變數p,指向線性表起始位置(頭結點)L。 int j = 0 ; while (p->next && j<pos-1) { //尋找第i個結點,並令p指向其前趨。 p = p->next ; ++j ; } if (!(p->next) || j>pos-1) // 刪除位置是否合法(結點存在,刪除的位置在表內) return ERROR ; LinkList q = p->next ; //使q指向i-1結點(將結點i-1中指向結點i的指標域,賦給指標變數q) p->next = q->next ; //(將結點i中指向結點i+1的指標域,賦給結點i-1的指標域 e = q->data ; //要刪除結點的資料域,賦給e free(q) ; //釋放指標變數q printf("刪除的元素:%d, 刪除的位置:%d\n", e, pos) ; return OK ; }// ListDelete_L 演算法2.10 // 初始條件:線性表L已存在。 // 操作結果:依次對L的每個資料元素呼叫函式visit()。一旦vistit()失敗,剛操作失敗。 Status visit(ElemType e) { printf("%d ",e) ; return OK ; } Status ListTraverse_L(LinkList L, Status (*pfn_visit)(ElemType)) { LinkList p = L->next ; //指標重新指向頭結點 if(!p) { printf("線性表未初始化。\n") ; return ERROR ; } while(p) { visit(p->data) ; p = p->next ; } printf("\n") ; return OK ; }// ListTraverse // 建立隨機表,包含10個隨機數(頭插法)。 Status CreateList(LinkList &L) { srand((unsigned)time(NULL)) ; //生成連結串列 L = (LinkList)malloc(sizeof(LNode)) ; if(!L) { //儲存分配失敗 printf("初始化失敗") ; exit(OVERFLOW) ; //exit(-1)程式異常退出 } for (int i=0 ; i<10 ; i++) { // 生成新結點 LinkList p = (LinkList)malloc(sizeof(LNode)) ; //scanf("%d", &p->data) ; //輸入元素值 賦給新生成結點的資料域 p->data = rand()%100 ; p->next = L->next ; //插入到表頭 L->next = p ; printf("%d ", p->data) ; // 檢視是否插入了新的元素 } return OK ; }// 個人整合 // 逆位序輸入(隨機產生)n個元素的值,建立帶表頭結點的單鏈線性表L(頭插法)。 void CreateList_L(LinkList &L, int n) { srand((unsigned)time(NULL)) ; //初始化隨機數種子 L = (LinkList)malloc(sizeof(LNode)) ; L->next = NULL ; //先建立一個帶頭結點的單鏈表 for (int i=n ; i>0 ; --i) { LinkList p = (LinkList)malloc(sizeof(LNode)) ;//生成新結點 //scanf("%d", &p->data) ; //輸入元素值 //隨機生成100以內的數字 p->data = rand()%100 ; //將生成的元素值賦給新生成結點的資料域 //插入到表頭 p->next = L->next ; //使新結點的指標域指向上一次生成的結點(將上一次生成結點的指標域賦給新結點的指標域) L->next = p ; //頭結點的指標域指向新生成的結點(將指向新結點的指標p賦給頭結點的指標域) } }// CreateList_L 演算法2.11 // 順位序輸入(隨機產生)n個元素的值,建立帶表頭結點的單鏈線性表L(尾插法)。 void CreateListTail(LinkList &L, int n) { srand((unsigned)time(NULL)) ; //初始化隨機數種子 L = (LinkList)malloc(sizeof(LNode)) ; L->next = NULL ; //先建立一個帶頭結點的單鏈表 for (int i=0 ; i<n ; ++i) { LinkList p = (LinkList)malloc(sizeof(LNode)) ; //scanf("%d", &p->data) ; //輸入元素值 p->data = rand()%100 ; //隨機生成100以內的數字,將生成的元素值賦給新生成結點的資料域 //插入到表尾 L->next = p ; //上一結點的指標域指向新生成的結點(將新生成結點的指標域賦給上一結點的指標的指標域) p->next = NULL ; //將新結點的指標域置空 } } // 初始化選單 void initMenu() { printf("\n\t\t*****************************************\n") ; printf("\n\t\t\t 線性表的鏈式表示和實現\n") ; printf("\n\t\t 1.建立隨機表\t\t 2.構造空線性表\n\t\t 3.銷燬線性表\t\t 4.清空線性表\n\t\t 5.線性表是否為空\t 6.線性表的長度") ; printf("\n\t\t 7.查詢表中元素\t 8.插入新元素\n\t\t 9.刪除某個元素\t 10.遍歷線性表\n\t\t 11.回到主選單\t\t 0.退出") ; } // 回到主選單 void mainMenu() { printf("\n\t\t*****************************************\n") ; printf("\n\t\t\t 歡迎回到主選單\n") ; printf("\n\t\t 1.建立隨機表\t\t 2.構造空線性表\n\t\t 3.銷燬線性表\t\t 4.清空線性表\n\t\t 5.線性表是否為空\t 6.線性表的長度") ; printf("\n\t\t 7.查詢表中元素\t 8.插入新元素\n\t\t 9.刪除某個元素\t 10.遍歷線性表\n\t\t 11.回到主選單\t\t 0.退出") ; } int main() { LinkList L ; InitList_L(L) ; initMenu() ; int select = -1 ; while(select != 0) { printf("\n請選擇你的操作:") ; scanf("%d", &select) ; switch(select) { case 1://建立隨機表 printf("請輸入要建立的隨機表元素個數:\n") ; int nElem ; scanf("%d", &nElem) ; CreateList_L(L, nElem) ; printf("建立隨機連結串列:") ; ListTraverse_L(L, visit) ; break ; case 2://構造空線性表 printf("構造一個空的線性表L。") ; InitList_L(L) ; ListTraverse_L(L, visit) ; break ; case 3://銷燬線性表 if(!L) {//線性表L的頭結點存在才能銷燬 printf("銷燬線性表L。\n") ; DestroyList_L(L) ; } else printf("線性表未初始化。\n") ; break ; case 4://清空線性表 printf("將L重置為空表。") ; ClearList_L(L) ; break ; case 5://線性表是否為空 if (ListEmpty_L(L)) printf("該線性表為空.\n") ; else printf("該線性表非空.\n") ; break ; case 6: { //線性表的長度 int lLength = ListLength_L(L) ; printf("線性表的長度為: %d \n", lLength) ; } break ; case 7: { //查詢表中元素 int nSearchOption = -1 ; while(nSearchOption) { printf("1.按位置查詢\t 2.按元素查詢\t 11.回到主選單\t 0.退出查詢\n請選擇你的操作:") ; scanf("%d", &nSearchOption) ; switch(nSearchOption) { case 1: { //1.按位置查詢 printf("請輸入要查詢的位置:") ; int pos ; ElemType e ; scanf("%d",&pos) ; if(GetElem_L(L, pos, e)) { printf("第%d個元素的值為:%d ", pos, e) ; ElemType pre_e, next_e ; if(PriorElem_L(L, e, pre_e)) printf("前一個元素:%d ", pre_e) ; else printf("前一個元素不存在 ") ; if(NextElem_Sq(L, e, next_e)) printf("後一個元素:%d \n", next_e) ; else printf("後一個元素不存在 \n") ; } else printf("請輸入正確的數字!!!\n") ; } break ; case 2: { //2.按元素查詢 printf("請輸入要查詢的元素:") ; int pos ; ElemType e ; scanf("%d", &e) ; // 這裡假定隨機陣列中的元素互不重複 pos = LocateElem_L(L, e, compare) ; if(pos) printf("值為%d是表中的第%d個元素\n", e, pos) ; else printf("沒有值為%d的元素\n", e) ; } break ; case 11://11.回到主選單 mainMenu() ; break; case 0://0.退出查詢 break; default: printf("請輸入正確的數字!!!\n"); break ; } } } break ; case 8: { //插入新元素 ElemType e ; int pos ; int nInsertOption ; nInsertOption = -1; while(nInsertOption) { printf("請輸入要插入的元素位置和元素的值:") ; scanf("%d %d", &pos, &e) ; if(ListInsert_L(L, pos, e)) { printf("插入完畢,現線上性表為:") ; ListTraverse_L(L, visit) ; } else printf("請輸入正確的數字!!!\n") ; printf("1.是 0.否 是否繼續: ") ; scanf("%d", &nInsertOption) ; } printf("\n") ; } break ; case 9: { //刪除某個元素 int nDeleteOption ; nDeleteOption = -1 ; while(nDeleteOption) { printf("1.按位置查詢\t 2.按元素查詢\t 11.回到主選單\t 0.退出查詢\n請選擇你的操作:") ; scanf("%d", &nDeleteOption) ; switch(nDeleteOption) { case 1: { //1.按位置刪除 ElemType e ; int pos ; printf("請輸入要刪除的位置:") ; scanf("%d", &pos) ; if(ListDelete_L(L, pos, e)) { printf("第%d個元素%d刪除完畢,現線上性表為:\n", pos, e) ; ListTraverse_L(L, visit) ; } else printf("請輸入正確的數字!!!\n") ; } break ; case 2: { //2.按元素刪除 printf("請輸入要刪除的元素:") ; ElemType e ; int pos ; scanf("%d", &e) ; // 這裡假定隨機陣列中的元素互不重複 pos = LocateElem_L(L, e, compare) ; if(pos) { ListDelete_L(L, pos, e) ; printf("第%d個元素%d刪除完結,現線上性表為:\n", pos, e) ; ListTraverse_L(L, visit) ; } else printf("沒有值為%d的元素\n", e) ; } break ; case 11://11.回到主選單 mainMenu() ; break; case 0://0.退出查詢 break; default: printf("請輸入正確的數字!!!\n"); break ; } } } break ; case 10://遍歷線性表 printf("遍歷線性表:") ; ListTraverse_L(L, visit) ; break ; case 11://回到主選單 mainMenu() ; break ; case 0://退出 break ; default: printf("請輸入正確的數字!!!\n") ; break ; } } return 0 ; }