您的位置:首页 > 理论基础 > 数据结构算法

【数据结构与算法】第三章 表c实现

2011-05-31 11:25 225 查看
表是一种常用的数据结构,它支持的基本操作有插入和删除。最基本地可以用数组来实现表结构,但因为数组中的数据都是连续存储的,若动态指定数组,会造成空间的浪费。而且在有序插入删除操作时,都需要调整元素在数组中的位置,因此,一般不使用数组来实现表结构。一般来说,使用链表来实现表结构。下面的程序中写了16个常用的链表函数,它源于http://www.bccn.net/Article/kfyy/cjj/jszl/200708/5227_2.html这篇文档,但上述文档中实现的是一个无表头的线性表结构。本文中对上述程序稍作修改,实现了一个有表头的链表结构。具体代码如下:

/*
* 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、对指针、引用、函数参数这几点的理解还不到位,需要继续吃透。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: