1. 程式人生 > >數據結構之線性表(嚴蔚敏《數據結構》要求)

數據結構之線性表(嚴蔚敏《數據結構》要求)

刪除 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 } 

數據結構之線性表(嚴蔚敏《數據結構》要求)