數據結構之線性表(嚴蔚敏《數據結構》要求)
阿新 • • 發佈:2018-07-24
刪除 fin 是我 sqlist 定義 code bug 分析 如果
1、每個代碼都是博主一個字一個敲出來的(有參考,但是我很認真的去分析了每個函數邏輯結構,並做了一定的修改)
2、函數都已經通過測試,沒有bug,符合要求
3、這裏只貼出代碼,代碼裏有些本人的理解和註釋,但是沒有那麽詳細
代碼分為
main.c
1 #include <stdio.h> 2 #include "fuction.h" 3 4 int main(void){ 5 Sqlist La; 6 Sqlist Lb; 7 Sqlist Lc; 8 int i=0; 9 int val_1 ; 10 Init_List( &La );11 List_Insert(&La, 1, 1); 12 List_Insert( &La, 2, 5 ); 13 List_Insert( &La, 3, 8 ); 14 List_Insert( &La, 4, 11 ); 15 List_Traverse( La, visit_printf ); 16 Init_List( &Lb ); 17 List_Insert( &Lb, 1, 2 ); 18 List_Insert( &Lb, 2, 6 ); 19 List_Insert( &Lb, 3, 8 ); 20 List_Insert( &Lb, 4, 9 ); 21 List_Insert( &Lb, 5, 11 ); 22 List_Insert( &Lb, 6, 15 ); 23 List_Insert( &Lb, 7, 20 ); 24 List_Traverse( Lb, visit_printf ); 25 Init_List( &Lc ); 26 Merge_List( La, Lb, &Lc );27 printf("單個輸出="); 28 visit_printf(Lc.pBase); 29 printf("\n"); 30 List_Traverse( Lc, visit_printf); 31 i = Locate_Elem( La, 8, compare_Elem); 32 printf("位序=%d\n", i); 33 34 Union(&La,Lb); 35 List_Traverse( La, visit_printf); 36 37 Prior_Elem( La, 5, &val_1) ; //當定義int *val_1 = 0 時候,作為實參進入卻沒發生錯誤。 38 printf("前驅=%d\n", val_1); //因為 指針初始化時指向一塊不能讀寫的內存,一般為0X00000000 39 Next_Elem( La, 5, &val_1) ; //如果對其進行操作,會發生錯誤 40 printf("前驅=%d\n", val_1); 41 42 List_Delete(&La,2,&val_1); 43 printf("刪除=%d\n", val_1); 44 45 Clear_List(&Lc); 46 i = List_Length(Lc); 47 printf("1---%d\n", i); 48 Destroy_List(&Lc); 49 i = List_Length(Lc); 50 printf("2---%d\n", i); 51 if( List_Empty(Lc) ) 52 printf("表是空的\n"); 53 54 return 0; 55 }
list_declaration.h
1 #ifndef LIST_DECLARATION 2 #define LIST_DECLARATION 3 #define TURE 1 4 #define FALSE 0 5 #define ERROR 0 6 #define OVERFLOW -2 7 #define MAX_SIZE 100 //初始化分配給線性表的長度,單位為(struct List) 8 #define ADD_SIZE 10 //線性表每次存儲空間增長的長度,單位為(struct List) 9 #define ElemType int 10 typedef int Status; 11 typedef struct List{ 12 int *pBase; //分配給線性表的存儲空間的首地址 13 int cnt; //線性表的使用長度 14 int len; //線性表的最大長度 15 }Sqlist,*pSqlist; 16 17 #endif //LIST_DECLARATION
fuction.h
1 /* 2 所有函數已經全通過測試,沒有BUG 3 */ 4 5 #include "list_declaration.h" 6 #ifndef FUCTION_H 7 #define FUCTION_H 8 //構造一個使用長度為空的線性表L 9 int Init_List( Sqlist *L ); 10 //初始條件:若線性表L已存在;操作結果:銷毀線性表L 11 int Destroy_List( Sqlist *L ); 12 //初始條件:若線性表L已存在;操作結果:把線性表置為空表 13 int Clear_List( Sqlist *L ); 14 //初始條件:若線性表L已存在;操作結果:若L為空表返回TURE,否則返回FALSE 15 int List_Empty( Sqlist L ); 16 //初始條件:若線性表L已存在;操作結果:返回L中數據元素個數 17 int List_Length( Sqlist L ); 18 //初始條件:若線性表L已存在,1<=pos<=len(L);操作結果:用e返回L中第pos個元素的值 19 int Get_Elem( Sqlist L, int pos, int *e ); 20 //初始條件:若線性表L已存在,compare()是數據元素判定函數 21 //操作結果:返回L中第1個與e滿足關系compare()的數據元素的位序,若這樣的數據元素不存在,則返回值為0 22 int Locate_Elem( Sqlist L, int pos, int (*compare)( int , int ) ); 23 //初始條件:若線性表L已存在; 24 //操作結果:若cur_e是L的數據元素,且不是第一個,則用pre_e返回它的前驅,否則操作失敗,pre_e無定義 25 int Prior_Elem( Sqlist L, int cur_e, int *pre_e ); 26 //初始條件:若線性表L已存在; 27 //操作結果:若cur_e是L的數據元素,且不是第一個,則用next_e返回它的前驅,否則操作失敗,next_e無定義 28 int Next_Elem( Sqlist L, int cur_e, int *next_e ); 29 //初始條件:若線性表L已存在,1<=pos<=len(L)+1; ??? 30 //操作結果:在L中第pos個位置之前插入新都數據元素e,L都長度加1 31 int List_Insert( Sqlist *L, int pos, int e ); 32 //初始條件:若線性表L已存在,1<=pos<=len(L); 33 //操作結果:刪除L第pos個數據元素,並用e返回其值,L都長度減1 34 int List_Delete( Sqlist *L, int pos, int *e ); 35 //初始條件:線性表L已存在 36 //操作結果:依次對L都每個數據元素調用函數visit()。一旦visit()失敗,則操作失敗 37 int List_Traverse( Sqlist L, void (*visit)( int* ) ); 38 //輸出地址e所指向內存的值 39 void visit_printf( int *e ); 40 //將存在於Lb中而不在La中的數據插入到La中去 41 void Union(Sqlist *La, Sqlist Lb); 42 //比較a,b的大小,若相等則返回1,否則返回0 43 int compare_Elem(int a, int b); 44 //初始條件:已知順序線性表La和Lb的元素按值非遞減排列 45 //操作結果:歸並La和Lb得到新的線性表Lc,Lc的元素也按值非遞減排列 46 void Merge_List(Sqlist La, Sqlist Lb,Sqlist *Lc); 47 48 #endif //FUCTION_H
fuction.c
1 /* 每個函數根據實際情況是否要返回值,制定返回值所對應的含義,一般不要中止整個程序的運行 */ 2 /* 代碼裏各個函數 關於Sqlist L 還是 Sqlist *L的選用問題 */ 3 /* Sqlist L: 多用於不需要改變L裏面的變量,只需要調用它們的值 */ 4 /* Sqlist *L: 多用於需要改變L裏面的變量的值 */ 5 /* 這麽做的原因是可以更直觀的表現一種思想,而如果不怕麻煩。可以運用 * 來解決這個問題,本質上無差別 */ 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <malloc.h> 9 #include "fuction.h" 10 11 int compare_Elem(int a, int b){ 12 if( a == b) 13 return TURE; 14 else 15 return FALSE; 16 } 17 void visit_printf( int *e ){ 18 printf("%d ", *e ); 19 } 20 int Init_List( Sqlist *L ){ //malloc()分配成功返回首地址,否則返回NULL 21 L->pBase = ( int* )malloc( sizeof(int) * MAX_SIZE ); 22 if( !L->pBase ) exit(OVERFLOW); //分配失敗 23 L->cnt = 0; 24 L->len = MAX_SIZE; 25 return TURE; 26 } 27 int Destroy_List( Sqlist *L ){ 28 free(L->pBase); //free(L->pBase)後,一定要L->pBase=NULL。以防出現野指針 29 L->pBase = NULL; //當L->pBase=NULL後,無論free()多少次都沒關系,否則2次會導致程序運行錯誤 30 L->cnt = 0; 31 L->len = 0; 32 return TURE; 33 } 34 int Clear_List( Sqlist *L ){ 35 L->cnt = 0; 36 return TURE; 37 } 38 int List_Empty( Sqlist L ){ 39 if( L.cnt == 0 ) 40 return TURE; 41 else 42 return FALSE; 43 } 44 int List_Length( Sqlist L ){ 45 return L.cnt; 46 } 47 int Get_Elem( Sqlist L, int pos, int *e ){ 48 if( pos < 1 || pos > L.cnt ) //return()是返回函數調用,從當前函數調用返回到主函數繼續執行 49 exit(ERROR); //exit() 表示退出當前進程/當前程序;不再執行 50 *e = *(L.pBase+pos-1); //或 *e = L.pBase[pos-1] ; 51 return TURE; 52 } 53 int Locate_Elem(Sqlist L, int e, int (*compare)( int , int )){//這個函數需要重點掌握,涉及到函數指針相關知識 54 int i = 1; 55 int *p = L.pBase; 56 while( i <= L.cnt && !compare( *p++, e ) ) i++; 57 if( i <= L.cnt ) 58 return i; 59 else 60 return 0; 61 } 62 int Prior_Elem( Sqlist L, int cur_e, int *pre_e ){ 63 int i = 2; 64 int *p = L.pBase + 1; 65 while( i <= L.cnt && *p != cur_e ){ // 2 至 cnt, 依次比較 66 p++; 67 i++; 68 } 69 if( i > L.cnt ) 70 return FALSE; 71 else{ 72 *pre_e = *--p; //前驅 73 return TURE; 74 } 75 } 76 int Next_Elem( Sqlist L, int cur_e, int *next_e ){ 77 int i=1; 78 int *p = L.pBase; 79 while( i < L.cnt && *p != cur_e ){ //1至cnt-1 依次比較 80 i++; 81 p++; 82 } 83 if( i == L.cnt ) 84 return FALSE; 85 else{ 86 *next_e = *++p; //後驅 87 return TURE; 88 } 89 } 90 int List_Insert( Sqlist *L, int pos, int e ){ 91 92 int i; 93 if( pos <1 || pos > L->len + 1 ) //這個L->len + 1 表示可以在表尾插入(追加) 94 return ERROR; 95 if (L->cnt >= L->len) { // 96 int* newBase = (int *) realloc(L->pBase,(L->len + ADD_SIZE) * sizeof(int)); 97 if (!newBase) { 98 printf("分配內存單元失敗"); 99 return 0; 100 } 101 L->pBase = newBase; 102 L->len += ADD_SIZE; 103 } 104 for( i = L->cnt ; i >= pos; i-- ) 105 L->pBase[i+1] = L->pBase[i]; 106 L->pBase[i] = e; //插入e 107 L->cnt++; //使用長度加1 108 return TURE; 109 } 110 int List_Delete( Sqlist *L, int pos, int *e ){ 111 int i = 0; 112 *e = L->pBase[pos-1]; 113 if( pos > 1 && pos < L->cnt ){ 114 for( i = pos; i < L->cnt; i++ ){ 115 L->pBase[i] = L->pBase[i+1]; 116 } 117 L->cnt--; 118 return TURE; 119 } 120 else 121 return ERROR; //pos 值不合法 122 } 123 int List_Traverse( Sqlist L, void (*vi)( int* ) ){ 124 int *p; //這個函數裏面的第三個參數是一個指向函數的函數指針vi。而它所指向的函數 125 int i; //這裏只是對函數指針的聲明,因此參數只需要給出數據類型就好 126 p = L.pBase; 127 for( i = 1; i <= L.cnt; i++){ //因為每個函數都有一個入口函數,就是函數名,有了函數名就可以調用函數 128 // 等價於vi(p++); //函數入口 與 函數之間 有調用機制(這個不管,知道有這回事就好) 129 (*vi)(p++); // vi 指向 visit_pritnf(入口函數)的首地址 130 } // 1、*vi 相當於取得 visit_pritnf 首地址; 2、vi = visit_pritnf 131 printf("\n"); //第一種是取地址,第二種是直接賦地址,因此是等效的 132 return TURE; 133 } 134 void Union(Sqlist *La, Sqlist Lb){ 135 int i; 136 int e; 137 int La_cnt; 138 int Lb_cnt; 139 La_cnt = List_Length(*La); Lb_cnt = List_Length(Lb); //求線性表的長度 140 for( i = 1; i <= Lb_cnt; i++ ){ //遍歷並獲取Lb中的元素 141 Get_Elem( Lb, i, &e ); 142 if( !Locate_Elem( *La, e, compare_Elem ) ) //La中不存在等於e的元素 143 List_Insert( La,++La_cnt, e ); //把這個e插入到La中 144 } 145 } 146 void Merge_List(Sqlist La, Sqlist Lb,Sqlist *Lc){ 147 //La和Lb已經存在的 148 int i = 1, j = 1, k = 0; 149 int ai,bi; 150 La.len = List_Length(La); //獲取La表使用長度 151 Lb.len = List_Length(Lb); //獲取Lb表使用長度 152 Init_List(Lc); 153 while( ( i <= La.len ) && ( j <= Lb.len ) ){ 154 Get_Elem( La, i, &ai ); Get_Elem( Lb, j, &bi ); //獲取La和Lb的元素 155 if( ai <= bi ) { List_Insert( Lc, ++k, ai ); ++i; } //比較獲取的元素,然後插入 156 else { List_Insert( Lc, ++k, bi ); ++j; } 157 } 158 while( i <= La.len ){//當La和Lb中任何一方提前全部插入,如不存在,則第一個循環就可以解決了 159 Get_Elem( La, i++, &ai ); List_Insert( Lc, ++k, ai ); 160 } 161 while( j <= Lb.len ){ 162 Get_Elem( Lb, j++, &bi ); List_Insert( Lc, ++k, bi ); 163 } 164 }
數據結構之線性表(嚴蔚敏《數據結構》要求)