【数据结构与算法】第三章 表c实现
2011-05-31 11:25
225 查看
表是一种常用的数据结构,它支持的基本操作有插入和删除。最基本地可以用数组来实现表结构,但因为数组中的数据都是连续存储的,若动态指定数组,会造成空间的浪费。而且在有序插入删除操作时,都需要调整元素在数组中的位置,因此,一般不使用数组来实现表结构。一般来说,使用链表来实现表结构。下面的程序中写了16个常用的链表函数,它源于http://www.bccn.net/Article/kfyy/cjj/jszl/200708/5227_2.html这篇文档,但上述文档中实现的是一个无表头的线性表结构。本文中对上述程序稍作修改,实现了一个有表头的链表结构。具体代码如下:
编程序时,值得注意的几点:
1、typedef定义结构体时:
此时Node是结构体地名称,我们可以用Node a;来定义一个Node类型的变量a,也可以用Node *pn;来定义一个指向Node类型变量的指针。上述的例子中,_Node是一个记号,当需要定义的结构体中包含一个指针,而这个指针类型为指向定义的结构体变量,那么这时候需要记号的辅助作用。
2、函数的参数类型应该注意,若需要改变传入的变量值,则需用指针或引用参数。如果不修改参数内容,则只需用值参数。
3、对指针、引用、函数参数这几点的理解还不到位,需要继续吃透。
/* * linear list implemention in c * with head * author: qiqi */ #include <stdio.h> #include <stdlib.h> #define NN 12 #define MM 20 typedef int ElementType; /* * Node struct */ typedef struct _Node { ElementType element; struct _Node* next; }Node; typedef Node * List; //1: 初始化线性表,即置单链表的表头指针为空 void initList( List *hl ) { *hl = ( Node * )malloc( sizeof( Node ) ); if( *hl == NULL ) perror( "Out of space!!!\n" ); (*hl)->element = 0; (*hl)->next = NULL; return; } //2: 清除线性表中所有元素,释放L中的所有结点,使之成为一个空表 void emptyList( List *hl ) { //cp 和 np分别为指向相邻结点的指针 Node *cp, *np; cp = (*hl)->next; while( cp != NULL ) { np = cp->next; free( cp ); cp = np; } //表头next元素置空 (*hl)->next = NULL; return; } //3: 返回单链表的长度 int sizeList( List hl ) { int count = 0; hl = hl->next; while ( hl != NULL ) { count++; hl = hl->next; } return count; } //4: 检查单链表是否为空,若为空,则返回1,否则返回0 int isEmpty( List hl ) { return hl->next == NULL; } //5: 返回单链表中第pos个结点中的元素,若pos超出范围,则停止程序进行 ElementType getElement( List hl, int pos ) { int i = 0; hl = hl->next; if( pos < 1 ) { printf("pos is not legal, quit!\n"); exit(1); } while( hl != NULL ) { i++; if( i == pos ) break; else hl = hl->next; } if( hl != NULL ) return hl->element; else { printf("pos is not legal, quit!\n"); exit(1); } } //6: 打印一个链表 void printList( List hl ) { hl = hl->next; while( hl != NULL ) { printf("%5d", hl->element); hl = hl->next; } printf("\n"); return; } //7: 在单链表中查找出现给定值x的第一个元素的位置 //若成功,则返回该结点data域的存储地址 //否则,返回NULL ElementType* findList( List hl, ElementType x ) { hl = hl->next; while( hl != NULL ) { if( hl->element == x ) return &(hl->element); else hl = hl->next; } return NULL; } //8: 把单链表中pos结点处的值修改为x的值 //若修改成功返回1,否则返回0 int updateList( List hl, int pos, ElementType x ) { int i = 0; Node * cp; cp = hl->next; while( cp != NULL ) { i++; if( pos == i ) break; else cp = cp->next; } if( pos == i ) { cp->element = x; return 1; } else return 0; } //9: 向单链表的表头插入一个元素 void insertFirstList( List *hl, ElementType x ) { Node * newCell; newCell = ( Node * )malloc( sizeof( Node ) ); if( newCell == NULL ) { perror("Out of space!!!\n"); exit(1); } newCell->element = x; newCell->next = (*hl)->next; (*hl)->next = newCell; return; } //10: 向单链表的末尾添加一个元素 void insertLastList( List *hl, ElementType x ) { Node * newCell; Node * cp; newCell = ( Node * )malloc( sizeof( Node ) ); if( newCell == NULL ) { perror("Out of space!!!\n"); exit(1); } newCell->element = x; newCell->next = NULL; cp = (*hl)->next; while( cp != NULL ) cp = cp->next; cp->next = newCell; return; }
//11: 向单链表pos个结点处插入元素为x的结点 //若成功,返回1,否则,返回0 int insertPosList( List *hl, int pos, ElementType x ) { Node * newCell; Node *cp, *pp; int i = 0; //还应该判断pos是不是超出链表的长度 if( pos <= 0 ) { perror("pos is not legal, quit!\n"); exit(1); } cp = (*hl)->next; while( cp != NULL ) { i++; if( pos == i ) break; else { //pp 为Pos前一个位置处 //cp 为pos位置处 pp = cp; cp = cp->next; } } newCell = ( Node * )malloc( sizeof( Node ) ); if( newCell == NULL ) { perror( "Out of space!!!\n"); return 0; } newCell->element = x; if( pos == i ) { newCell->next = cp; pp->next = newCell; } else { perror("pos is not legal, quit\n"); return 0; } return 1; } //12: 向有序单链表中插入元素x结点,使得插入后仍然有序 void insertOrderList( List *hl, ElementType x ) { Node *cp, *pp; Node *newCell; cp = (*hl)->next; pp = NULL; newCell = ( Node * )malloc( sizeof( Node ) ); if( newCell == NULL ) { perror("Out of space!!!\n"); exit(1); } newCell->element = x; //将新的结点插入到1的位置,即表头元素之后 if( cp == NULL || x < cp->element) { newCell->next = cp; (*hl)->next = newCell; return; } while( cp != NULL ) { if( x < cp->element ) break; else { pp = cp; cp = cp->next; } } newCell->next = cp; pp->next = newCell; return; } //13: 删除单链表中第一个元素,并把该结点值返回 ElementType deleteFirstList( List *hl ) { ElementType temp; Node * cp = (*hl)->next; if( cp == NULL ) { printf("单链表为空,没有元素\n"); exit(1); } (*hl)->next = cp->next; temp = cp->element; free(cp); return temp; } //14: 从单链表中删除尾部结点,并返回该结点值 ElementType deleteLastList( List *hl ) { ElementType temp; Node *cp, *pp; cp = (*hl)->next; pp = NULL; if( cp == NULL ) { printf("单链表为空,没有元素可删除.\n"); exit(1); } while( cp->next != NULL ) { pp = cp; cp = cp->next; } //若单链表中只有一个结点 if( pp == NULL ) { (*hl)->next = cp->next; } else { pp->next = NULL; } temp = cp->element; free(cp); return temp; } //15: 从单链表中删除第pos个结点,并返回其值 ElementType deletePosList( List *hl, int pos ) { int i = 0; ElementType temp; Node *cp, *pp; cp = (*hl)->next; pp = NULL; if( ( cp == NULL ) || ( pos <= 0 ) ) { printf("单链表为空或pos值不正确,退出运行.\n"); exit(1); } //单链表中找出pos个结点,找到后cp指向该结点,pp指向其前驱结点 while( cp != NULL ) { i++; if( i == pos ) break; else { pp = cp; cp = cp->next; } } //单链表中没有pos结点 if( cp == NULL ) { printf("pos值不正确\n"); exit(1); } //若pos=1,需要删除第一个结点 if( pos == 1 ) (*hl)->next = cp->next; else pp->next = cp->next; temp = cp->element; free(cp); return temp; } //16: 从单链表中删除值为x的第一个结点 //成功返回1,否则返回0 int deleteValueList( List *hl, ElementType x ) { Node *pp, *cp; cp = (*hl)->next; pp = NULL; while( cp != NULL ) { if( cp->element == x ) break; else { pp = cp; cp = cp->next; } } //查找失败 if( cp == NULL ) return 0; //如果删除的是表头元素 if( pp == NULL ) (*hl)->next = cp->next; else pp->next = cp->next; free(cp); return 1; } /*********************************************** ***********************************************/ int main( int argc, char* argv[] ) { int a[NN]; int i; Node *p, *h, *s; srand( time( NULL ) ); initList( &p ); for( i = 0; i < NN; i++ ) a[i] = rand() & MM; printf("随机数序列: "); for( i = 0; i < NN; i++ ) printf("%5d", a[i]); printf("\n"); printf("随机数逆序: "); for( i = 0; i < NN; i++ ) insertFirstList( &p, a[i] ); printList( p ); printf("单链表长度: %5d\n", sizeList( p ) ); //删除链表元素测试 //p指向生成的逆序数列 for( h = p; h->next != NULL; h = h->next ) { while( deleteValueList( &(h->next), (h->next)->element ) ) { ; } } printf("删除链表元素: "); printList( p ); printf("单链表长度: %5d\n", sizeList( p ) ); h = NULL; initList( &h ); for( s = p->next; s != NULL; s = s->next ) { insertOrderList( &h, s->element ); } printf("有序表序列: "); printList( h ); emptyList( &h ); return 0; }
编程序时,值得注意的几点:
1、typedef定义结构体时:
typedef int Element; typedef struct _Node { ElementType element; struct _Node * next; }Node;
此时Node是结构体地名称,我们可以用Node a;来定义一个Node类型的变量a,也可以用Node *pn;来定义一个指向Node类型变量的指针。上述的例子中,_Node是一个记号,当需要定义的结构体中包含一个指针,而这个指针类型为指向定义的结构体变量,那么这时候需要记号的辅助作用。
2、函数的参数类型应该注意,若需要改变传入的变量值,则需用指针或引用参数。如果不修改参数内容,则只需用值参数。
3、对指针、引用、函数参数这几点的理解还不到位,需要继续吃透。
相关文章推荐
- 【数据结构与算法】第三章 表c实现应用一-----------多项式
- 【数据结构与算法】第三章 栈c实现,使用链表结构
- 【数据结构与算法】自己动手实现图的BFS和DFS(附完整源码)
- 常用查找数据结构及算法(Python实现)
- 数据结构与算法---C#实现LinkedList实例
- 数据结构——第三章算法设计题(2):判断是否为回文
- 数据结构——快速排序原理及算法Java实现
- 【数据结构与算法】左偏树(堆)的实现
- 数据结构与算法——不相交集类的C++实现
- 数据结构与算法——B树的C++实现
- clojure 数据结构与算法 第一篇 lz77算法的实现
- 【数据结构与算法】【排序】堆排序的代码实现
- 数据结构之---C语言实现最小生成树之prim(普里姆)算法
- 散列表的实现 -- 数据结构与算法的javascript描述 第八章
- 【数据结构与算法】自己动手实现图的BFS和DFS(附完整源码)
- 数据结构与算法学习笔记——链表部分实现(数组形式)
- 【数据结构作业一】写出顺序表的结构体类型定义及查找、插入、删除算法,并以顺序表作存储结构,实现线性表的插入、删除
- Java数据结构与算法---栈的实现
- 数据结构与算法——图的邻接表表示法类的C++实现
- 数据结构与算法Java版——单链表的实现