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"); }