4.1 指針 node
實際上並不推薦使用malloc和free,使用malloc還簡單,可是當指針進行移動的時候,你如何肯定在哪一個地址上free內存,則是個大難題. 算法
咱們寫個正常的malloc和free程序: 編程
#include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { int *pi = ( int * )malloc( sizeof( int ) ); *pi = 4; printf("%d\n", *pi ); free( pi ); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char **pstr = ( char ** )malloc( sizeof( char ) * 100 ); *pstr = "hello world"; printf("%s\n", *pstr ); free( pstr ); return 0; }
1. 對於char *,最好理解爲字符串,而不是字符指針(雖然操做的時候,能夠經過字符指針進行操做) 數組
2. 對於malloc函數,要分配肯定的大小,因此程序中爲sizeof(char)而不是sizeof(char*),由於指針在特定的機子上的大小不一樣(通常爲4字節) 數據結構
3. 在free中,必定要找對free的起始地址.好比我若是這樣修改,則會報錯: 模塊化
#include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char **pstr = ( char ** )malloc( sizeof( char ) * 100 ); *pstr = "hello world"; printf("%c---%s---%p\n", **pstr, *pstr, pstr ); pstr++; free( pstr ); return 0; }
你能確保在編寫代碼中,用到free的時候,不會一不當心的移動了一下指針??至少我基本不敢用free,也是這個緣由.這也致使了實際上我也不太敢用malloc. 函數
4.2 鏈表 性能
簡單寫一個單鏈表,數據元素爲字符串,支持增長,刪除,查找.按字符串的字典順序排序. 設計
PS:實際上這裏的難度在於:C語言只能傳值,因此你必須傳遞指針的指針到函數中去.而傳遞指針的指針也很麻煩,那麼咱們能夠這樣想:用一個固定的節點看成頭指針,而實際的頭節點看成第二個指針便可: 指針
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct LINK{ char *word; struct LINK *next; }Link; void insert( Link *link, char *word ) { Link *temp = ( Link * )malloc( sizeof( Link ) ); //用於存儲新的值 Link *tempLink = ( Link * )malloc( sizeof( Link ) ); //在插入節點時存儲上一個節點 temp->word = word; temp->next = NULL; if ( NULL == link->next ){ link->next = temp; } else{ tempLink = link; //存儲上一個節點 link = link->next; while ( NULL != link ){ if ( -1 == strcmp( link->word, word ) ){ tempLink = link; link = link->next; } else if ( 0 == strcmp( link->word, word ) ){ return; } else{ temp->next = link; tempLink->next = temp; return; } } if ( NULL == link ){ //判斷爲尾節點的特殊狀況 tempLink->next = temp; } } } int delete( Link *link, char *word ) { Link *tempLink = ( Link * )malloc( sizeof( Link ) ); //用於存儲刪除元素的上一個節點 tempLink = link; link = link->next; while ( NULL != link ){ if ( 0 != strcmp( link->word, word ) ){ tempLink = link; link = link->next; } else{ tempLink->next = link->next; return 1; } } return 0; } void show( Link *link ){ while ( NULL != link ){ printf("%s-->", link->word ); link = link->next; } printf("NULL\n"); } int main( void ) { Link *link = ( Link * )malloc( sizeof( Link ) ); link->next = NULL; link->word = "EOF"; //這裏假定沒有字符串等於EOF insert( link, "cc" ); insert( link, "dd" ); insert( link, "aa" ); insert( link, "bb" ); insert( link, "ba" ); insert( link, "cb" ); show( link->next ); delete( link, "bb" ); delete( link, "dd" ); delete( link, "ff" ); show( link->next ); return 0; }
有道題比較難(真的寫的時候也不難,只是以前我沒寫出來,如今寫出來罷了),就是將鏈表進行翻轉,但不能借助其餘的存儲空間(若是能的話,至關於對delete一個鏈表再insert成一個鏈表),代碼以下:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct LINK{ char *word; struct LINK *next; }Link; void insert( Link *link, char *word ) { Link *temp = ( Link * )malloc( sizeof( Link ) ); //用於存儲新的值 Link *tempLink = ( Link * )malloc( sizeof( Link ) ); //在插入節點時存儲上一個節點 temp->word = word; temp->next = NULL; if ( NULL == link->next ){ link->next = temp; } else{ tempLink = link; //存儲上一個節點 link = link->next; while ( NULL != link ){ if ( -1 == strcmp( link->word, word ) ){ tempLink = link; link = link->next; } else if ( 0 == strcmp( link->word, word ) ){ return; } else{ temp->next = link; tempLink->next = temp; return; } } if ( NULL == link ){ //判斷爲尾節點的特殊狀況 tempLink->next = temp; } } } int delete( Link *link, char *word ) { Link *tempLink = ( Link * )malloc( sizeof( Link ) ); //用於存儲刪除元素的上一個節點 tempLink = link; link = link->next; while ( NULL != link ){ if ( 0 != strcmp( link->word, word ) ){ tempLink = link; link = link->next; } else{ tempLink->next = link->next; return 1; } } return 0; } void show( Link *link ){ while ( NULL != link ){ printf("%s-->", link->word ); link = link->next; } printf("NULL\n"); } void reverse( Link *link ) { Link *tail = ( Link * )malloc( sizeof( Link ) ); Link *mid = ( Link * )malloc( sizeof( Link ) ); Link *prev = ( Link * )malloc( sizeof( Link ) ); Link *head = ( Link * )malloc( sizeof( Link ) ); head = link; tail = NULL; link = link->next; if ( NULL != link ){ mid = link; prev = link->next; while ( NULL != prev ){ mid->next = tail; tail = mid; mid = prev; prev = prev->next; } mid->next = tail; head->next = mid; } } int main( void ) { Link *link = ( Link * )malloc( sizeof( Link ) ); link->next = NULL; link->word = "EOF"; //這裏假定沒有字符串等於EOF insert( link, "cc" ); insert( link, "dd" ); insert( link, "aa" ); insert( link, "bb" ); insert( link, "ba" ); insert( link, "cb" ); show( link->next ); delete( link, "bb" ); delete( link, "dd" ); delete( link, "ff" ); show( link->next ); reverse( link ); show( link->next ); return 0; }
4.3 動態鏈棧與動態鏈隊列
動態鏈棧與動態鏈隊列沒什麼特別的地方,主要就是多個鏈棧的集合而已,而傳遞的時候只要把每一個棧的地址傳遞到函數裏面去就能夠了.
4.4 多項式
多項式的相加:書上的方法很牛,它是直接返回一個地址的.效率在我看來,是全部多項式相加里面最高的.可是我我的感受,代碼應該簡潔,更應該有良好的閱讀感.因此我打算是將相加的結果看成一個指針傳遞進去,而不是從函數內返回回來:
先把本身寫的錯誤的代碼粘貼出來,用於銘記(對待C,C++,都要用及其認真的態度來對待):
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct POLYNODE{ int coef; int expon; struct POLYNODE *next; }PolyNode; void padd( PolyNode *exp1, PolyNode *exp2, PolyNode *exp ) { PolyNode *addNode; while ( exp1 && exp2 ){ addNode = ( PolyNode * )malloc( sizeof( PolyNode ) ); if ( exp1->expon < exp2->expon ){ addNode->coef = exp2->coef; addNode->expon = exp2->expon; addNode->next = NULL; exp = addNode; exp = exp->next; exp2 = exp2->next; continue; } else if ( exp1->expon == exp2->expon ){ if ( 0 == ( exp1->coef + exp2->coef ) ){ exp1 = exp1->next; exp2 = exp2->next; continue; } addNode->coef = exp1->coef + exp2->coef; addNode->expon = exp1->expon; addNode->next = NULL; exp = addNode; exp = exp->next; exp1 = exp1->next; exp2 = exp2->next; continue; } else{ addNode->coef = exp1->coef; addNode->expon = exp1->expon; addNode->next = NULL; exp = addNode; exp = exp->next; exp1 = exp1->next; continue; } } while ( exp1 ){ addNode = ( PolyNode * )malloc( sizeof( PolyNode ) ); addNode->coef = exp1->coef; addNode->expon = exp1->expon; addNode->next = NULL; exp = addNode; exp = exp->next; exp1 = exp1->next; } while ( exp2 ){ addNode = ( PolyNode * )malloc( sizeof( PolyNode ) ); addNode->coef = exp2->coef; addNode->expon = exp2->expon; addNode->next = NULL; exp = addNode; exp = exp->next; exp2 = exp2->next; } } void show( PolyNode *exp ) { exp = exp->next; while ( exp ){ printf("%d * x^%d + ", exp->coef, exp->expon ); exp = exp->next; } printf("0\n"); } int main( void ) { PolyNode *exp1 = ( PolyNode * )malloc( sizeof( PolyNode ) ); PolyNode *exp2 = ( PolyNode * )malloc( sizeof( PolyNode ) ); PolyNode *exp = ( PolyNode * )malloc( sizeof( PolyNode ) ); PolyNode node1_1, node1_2, node1_3, node2_1, node2_2, node2_3; exp1->next = NULL; exp2->next = NULL; exp->next = NULL; node1_1.coef = 3; node1_1.expon = 14; node1_1.next = &node1_2; node1_2.coef = 2; node1_2.expon = 8; node1_2.next = &node1_3; node1_3.coef = 1; node1_3.expon = 0; node1_3.next = NULL; node2_1.coef = 8; node2_1.expon = 14; node2_1.next = &node2_2; node2_2.coef = -3; node2_2.expon = 10; node2_2.next = &node2_3; node2_3.coef = 10; node2_3.expon = 6; node2_3.next = NULL; exp1->next = &node1_1; exp2->next = &node2_1; padd( exp1->next, exp2->next, exp->next ); show( exp ); return 0; }
1. 必定要把頭指針傳遞進去:
padd( exp1, exp2, exp );
exp = addNode; exp = exp->next;
因此代碼修改以下(模塊化):
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct POLYNODE{ int coef; int expon; struct POLYNODE *next; }PolyNode; void insert( PolyNode *exp, PolyNode *addNode ) { if ( NULL == exp->next ){ exp->next = addNode; } else{ exp = exp->next; while ( NULL != exp->next ){ exp = exp->next; } exp->next = addNode; } } void padd( PolyNode *exp1, PolyNode *exp2, PolyNode *exp ) { PolyNode *addNode; while ( exp1 && exp2 ){ addNode = ( PolyNode * )malloc( sizeof( PolyNode ) ); if ( exp1->expon < exp2->expon ){ addNode->coef = exp2->coef; addNode->expon = exp2->expon; addNode->next = NULL; insert( exp, addNode ); exp2 = exp2->next; continue; } else if ( exp1->expon == exp2->expon ){ if ( 0 == ( exp1->coef + exp2->coef ) ){ exp1 = exp1->next; exp2 = exp2->next; continue; } addNode->coef = exp1->coef + exp2->coef; addNode->expon = exp1->expon; addNode->next = NULL; insert( exp, addNode ); exp1 = exp1->next; exp2 = exp2->next; continue; } else{ addNode->coef = exp1->coef; addNode->expon = exp1->expon; addNode->next = NULL; insert( exp, addNode ); exp1 = exp1->next; continue; } } while ( exp1 ){ addNode = ( PolyNode * )malloc( sizeof( PolyNode ) ); addNode->coef = exp1->coef; addNode->expon = exp1->expon; addNode->next = NULL; insert( exp, addNode ); exp1 = exp1->next; } while ( exp2 ){ addNode = ( PolyNode * )malloc( sizeof( PolyNode ) ); addNode->coef = exp2->coef; addNode->expon = exp2->expon; addNode->next = NULL; insert( exp, addNode ); exp2 = exp2->next; } } void show( PolyNode *exp ) { exp = exp->next; while ( exp ){ printf("%d * x^%d + ", exp->coef, exp->expon ); exp = exp->next; } printf("0\n"); } int main( void ) { PolyNode *exp1 = ( PolyNode * )malloc( sizeof( PolyNode ) ); PolyNode *exp2 = ( PolyNode * )malloc( sizeof( PolyNode ) ); PolyNode *exp = ( PolyNode * )malloc( sizeof( PolyNode ) ); PolyNode node1_1, node1_2, node1_3, node2_1, node2_2, node2_3; exp1->next = NULL; exp2->next = NULL; exp->next = NULL; node1_1.coef = 3; node1_1.expon = 14; node1_1.next = &node1_2; node1_2.coef = 2; node1_2.expon = 8; node1_2.next = &node1_3; node1_3.coef = 1; node1_3.expon = 0; node1_3.next = NULL; node2_1.coef = 8; node2_1.expon = 14; node2_1.next = &node2_2; node2_2.coef = -3; node2_2.expon = 10; node2_2.next = &node2_3; node2_3.coef = 10; node2_3.expon = 6; node2_3.next = NULL; exp1->next = &node1_1; exp2->next = &node2_1; padd( exp1->next, exp2->next, exp ); show( exp ); return 0; }
多項式的循環鏈表中,涉及到一個很是有用的概念:內存池.就是分配一塊內存用於存儲和刪除,這樣就沒必要每次malloc了.可是這裏內存池實際上能夠用數組來實現(堆棧),這樣更加的方便.因而本身寫了如下的算法:
PS:這裏爲了簡單的討論,鏈表的插入就直接在頭部插入了,並且並非循環鏈表:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_STACK 100 typedef struct NODE{ int data; struct NODE *next; }Node; Node stack[ MAX_STACK ]; int top = 0; void insert( Node *node, int data ) { Node *tempnode; if ( top == MAX_STACK - 1 ){ printf("sorry. 木有內存空間了\n"); return; } tempnode = &stack[ top++ ]; //這樣作只是爲了top能及時的++ tempnode->data = data; tempnode->next = NULL; if ( NULL == node->next ){ node->next = tempnode; } else{ tempnode->next = node->next; node->next = tempnode; } } void show( Node *node ) { node = node->next; while ( node ){ printf("%d->", node->data ); node = node->next; } printf("NULL\n"); } int main( void ) { Node node = stack[ top++ ]; node.next = NULL; insert( &node, 1 ); insert( &node, 2 ); insert( &node, 3 ); insert( &node, 4 ); insert( &node, 5 ); show( &node ); return 0; }
若是你手賤的話,可能會寫出下列的代碼(個人初版本---結果調試的時候發現指針亂竄):
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_STACK 100 typedef struct NODE{ int data; struct NODE *next; }Node; Node stack[ MAX_STACK ]; int top = 0; void insert( Node *node, int data ) { Node tempnode; if ( top == MAX_STACK - 1 ){ printf("sorry. 木有內存空間了\n"); return; } tempnode = stack[ top++ ]; //這樣作只是爲了top能及時的++ tempnode.data = data; tempnode.next = NULL; if ( NULL == node->next ){ node->next = &tempnode; } else{ tempnode.next = node->next; node->next = &tempnode; } } void show( Node *node ) { node = node->next; while ( node ){ printf("%d->", node->data ); node = node->next; } printf("NULL\n"); } int main( void ) { Node node = stack[ top++ ]; node.next = NULL; insert( &node, 1 ); insert( &node, 2 ); insert( &node, 3 ); insert( &node, 4 ); insert( &node, 5 ); show( &node ); return 0; }你會發現tempnode的地址實際上會指向以前賦值的node,而後tempnode不斷的被更改,就是實際上:
tempnode = stack[ top++ ];
並無達到你想要的效果.
4.5 鏈表的其餘操做
1. 翻轉單鏈表---在上面已經寫過了.
2. 串接單鏈表---把第二個鏈表的頭節點放在第一個鏈表的尾節點便可.
4.6 等價關係
關於等價關係,我並不瞭解書上的那個VLSI的應用場景,因此略過.
4.7 稀疏矩陣
書上用稀疏矩陣的數據結構過於麻煩,直接不想看.在編程的世界裏,有幾點必須注意:1. 儘可能把代碼寫簡單.2.性能沒有你想象中的那麼重要,可維護性在某些方面更加劇要.因此,在作項目的時候,若是性能沒有那麼重要,推薦使用高級語言,不要使用C.C只是用來打基礎的.
4.8 雙向鏈表
最後以一個雙向鏈表的實現來結束本章(這裏只是簡單的實現,並無設計到排序等狀況.鏈表的做用是用於存儲,若是關聯到排序,請使用二叉樹.這裏要用循環鏈表實現,不然你得維護兩張鏈表):
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct DLINK{ int data; struct DLINK *prev; struct DLINK *next; }Dlink; void insertFront( Dlink *dlink, int data ); void insertTail( Dlink *dlink, int data ); void delete( Dlink *dlink, int data ); int search( Dlink *dlink, int data ); void show( Dlink *dlink ); int main( void ) { int i = 0; Dlink *dlinkHead = ( Dlink * )malloc( sizeof( Dlink ) ); dlinkHead->next = dlinkHead->prev = NULL; for ( i = 0; i < 10; i++ ){ insertFront( dlinkHead, i ); insertTail( dlinkHead, i ); } for ( i = 0; i < 10; i += 3 ){ delete( dlinkHead, i ); } if ( search( dlinkHead, 5 ) ){ printf("5 in the double link list\n"); } else{ printf("5 not in the double link list\n"); } if ( search( dlinkHead, 3 ) ){ printf("3 in the double link list\n"); } else{ printf("3 not in the double link list\n"); } show( dlinkHead ); return 0; } void insertFront( Dlink *dlink, int data ) { Dlink *tempDlink = ( Dlink * )malloc( sizeof( Dlink ) ); tempDlink->data = data; if ( ( NULL == dlink->prev ) && ( NULL == dlink->next ) ){ dlink->prev = tempDlink; dlink->next = tempDlink; } else{ dlink->next->prev = tempDlink; tempDlink->prev = NULL; //用於判斷鏈表的頭部 tempDlink->next = dlink->next; dlink->next = tempDlink; } } void insertTail( Dlink *dlink, int data ) { Dlink *tempDlink = ( Dlink * )malloc( sizeof( Dlink ) ); tempDlink->data = data; if ( ( NULL == dlink->prev ) && ( NULL == dlink->next ) ){ dlink->prev = tempDlink; dlink->next = tempDlink; } else{ tempDlink->prev = dlink->prev; tempDlink->next = NULL; //用於判斷鏈表的尾部 dlink->prev->next = tempDlink; dlink->prev = tempDlink; } } void delete( Dlink *dlink, int data ) { Dlink *headNode = ( Dlink * )malloc( sizeof( Dlink ) ); headNode = dlink; //用於存儲頭節點 if ( ( NULL == dlink->prev ) && ( NULL == dlink->next ) ){ return; } dlink = dlink->next; while ( dlink->next ){ if ( data != dlink->data ){ dlink = dlink->next; } else{ if ( NULL == dlink->prev ){ headNode->next = dlink->next; dlink->prev = NULL; } else if ( NULL == dlink->next ){ headNode->prev = dlink->prev; dlink->prev->next = NULL; } else{ dlink->next->prev = dlink->prev; dlink->prev->next = dlink->next; } dlink = dlink->next; } } } int search( Dlink *dlink, int data ) { dlink = dlink->next; while ( dlink ){ if ( data == dlink->data ){ return 1; } dlink = dlink->next; } return 0; } void show( Dlink *dlink ) { dlink = dlink->next; while ( dlink ){ printf("%d-->", dlink->data ); dlink = dlink->next; } printf("NULL\n"); }