c语言的链表实现,C语言:链表实现的一个实例

问题:写一个程序输入你一年看过的所有电影以及每部电影的各种信息(简化问题:每部电影只要求输入片名和评价)

链表实现:

#include

#include//提供malloc()原型

#include

#define TSIZE 45

struct film{

char title[TSIZE];

int rating;

struct film * next;

};

int main()

{

struct film * head = NULL;

struct film * prev, *current;

char input[TSIZE];

//收集并储存信息

puts("Enter first movie title:");

while(gets(input)!=NULL&&input[0]!='\0'){

current = (struct film *)malloc(sizeof(struct film));

if(head==NULL)

head=current;

else

prev->next=current;

current->next=NULL;

strcpy(current->title, input);

puts("Enter your rating <0-10>:");

scanf("%d",&current->rating);

while(getchar()!='\n')

continue;

puts("Enter next movie title(empty line to stop):");

prev=current;

}

//给出电影列表

if(head==NULL)

printf("No data entered.");

else

printf("Here is the movie list:\n");

current=head;

while(current!=NULL){

printf("Movie:%s Rating:%d\n",current->title,current->rating);

current=current->next;

}

//释放所分配的内存

current=head;

while(current!=NULL){

free(current);

current=current->next;

}

printf("Bye!\n");

return 0;

}

程序分析:

不使用head遍历整个列表而使用一个新指针current是因为head会改变head的值,这样程序将不再能找到列表的开始处。

由malloc()分配的内存在程序终止时虽然会自动清理,但仍要记得调用free()来释放malloc()分配的内存,养成良好的习惯。

反思:

程序没有检查malloc()是否找到需要的内存,并且没有提供删除列表中项目的功能。

抽象数据类型实现:

1.构造接口

list.h接口文件

#ifndef LIST_H_

#define LIST_H_

#include

/*特定程序的声明*/

#define TSIZE 45

struct film

{

char title[TSIZE];

int rating;

};

/*一般类型定义*/

typedef struct film Item;

typedef struct node

{

Item item;

struct node * next;

}Node;

typedef Node * List;

/*函数原型*/

/*操作:初始化一个列表*/

/*操作前:plist指向一个列表*/

/*操作后:该列表被初始化为空列表*/

void InitializeList(List * plist);

/*操作:确定列表是否为空列表*/

/*操作前:plist指向一个已初始化的列表*/

/*操作后:如果该列表为空则返回true;否则返回false*/

bool ListIsEmpty(const List * plist);

/*操作:确定列表是否已满*/

/*操作前:plist指向一个已初始化的列表*/

/*操作后:如果该列表为空则返回true;否则返回false*/

bool ListIsFull(const List * plist);

/*操作:确定列表中项目的个数*/

/*操作前:plist指向一个已初始化的列表*/

/*操作后:返回该列表中项目的个数*/

unsigned int ListItemCount(const List * plist);

/*操作:在列表尾部添加一个项目*/

/*操作前:item是要被增加到列表的项目 plist指向一个已初始化的列表*/

/*操作后:如果可能的话,在列表尾部添加一个新项目,函数返回true,否则函数返回false*/

bool AddItem(Item item,List * plist);

/*操作:把一个函数作用于列表中的每个项目*/

/*操作前:plist指向一个已初始化的列表 pfun指向一个函数,该函数接受一个Item参数并且无返回值*/

/*操作后:pfun指向的函数被作用到列表中的每个项目一次*/

void Traverse(const List * plist,void(* pfun)(Item item));

/*操作:释放已分配的内存(如果有)*/

/*操作前:plist指向一个已初始化的列表*/

/*操作后:为该列表分配的内存已被释放并且该列表被置为空列表*/

void EmptyTheList(List * plist);

#endif

2.实现接口:

list.c文件

#include

#include

#include "list.h"

/*局部函数原型*/

static void CopyToNode(Item item,Node * pnode);

/*接口函数*/

/*把列表设置为空列表*/

void InitializeList(List * plist)

{

* plist = NULL;

}

/*如果列表为空则返回真*/

bool ListIsEmpty(const List * plist)

{

if(* plist == NULL)

return true;

else

return false;

}

/*如果列表已满则返回真*/

bool ListIsFull(const List * plist)

{

Node * pt;

bool full;

pt = (Node *)malloc(sizeof(Node));

if(pt==NULL)

full=true;

else

full=false;

free(pt);

return full;

}

/*返回节点数*/

unsigned int ListItemCount(const List * plist)

{

unsigned int count = 0;

Node * pnode = *plist;

while(pnode!=NULL)

{

++count;

pnode=pnode->next;

}

return count;

}

/*创建存放项目的节点,并把它添加到由plist指向的列表(较慢的实现方法)尾部*/

bool AddItem(Item item,List * plist)

{

Node * pnew;

Node * scan = *plist;

pnew = (Node *)malloc(sizeof(Node));

if(pnew==NULL)

return false;

CopyToNode(item,pnew);

pnew->next=NULL;

if(scan==NULL)

*plist=pnew;

else

{

while(scan->next!=NULL)

scan=scan->next;

scan->next=pnew;

}

return true;

}

/*访问每个节点并对它们分别执行由pfun指向的函数*/

void Traverse(const List * plist,void(*pfun)(Item item))

{

Node *pnode=*plist;

while(pnode!=NULL)

{

(*pfun)(pnode->item);

pnode=pnode->next;

}

}

/*释放由malloc()分配的内存*/

/*把列表指针设置为NULL*/

void EmptyTheList(List * plist)

{

Node * psave;

while(*plist!=NULL)

{

psave=(*plist)->next;

free(*plist);

*plist=psave;

}

}

/*局部函数定义*/

/*把一个项目复制到一个节点中*/

static void CopyToNode(Item item,Node *pnode)

{

pnode->item=item;

}

3.使用接口:

film.c

#include

#include

#include "list.h"

void showmovies(Item item);

int main(void)

{

List movies;

Item temp;

/*初始化*/

InitializeList(&movies);

if(ListIsFull(movies))

{

fprintf(stderr, "No memory available!Bye!\n");

exit(1);

}

/*收集并存储*/

puts("Enter first movie title:");

while(gets(temp.title)!=NULL && temp.title[0]!='\0')

{

puts("Enter your rating<0-10>:");

scanf("%d",&temp.rating);

while(getchar()!='\n')

continue;

if(AddItem(temp,&movies)==false)

{

fprintf(stderr,"Problem allocating memory\n");

break;

}

if(ListIsFull(movies))

{

puts("The list if now full.");

break;

}

puts("Enter next movie title(empty line to stop):");

}

/*显示*/

if(ListIsEmpty(movies))

printf("No data entered.");

else

{

printf("Here is the movie list:\n");

Traverse(&movies,showmovies);

}

printf("You entered %d movies.\n",ListItemCount(&movies));

/*清除*/

EmptyTheList(&movies);

printf("Bye!\n");

return 0;

}

void showmovies(Item item)

{

printf("Movies:%s Rating:%d\n",item.title,item.rating);

}

注意:

整个程序由三个文件组成,要运行这个程序,必须编译并链接film.c和list.c(关于编译多文件程序),工程建立如下:

9fec0eee673eb665a95c8217d5a03339.png

反思:

使用ADT方法带来了什么?

1.使用链表的方式暴露了所有编程的细节,而使用ADT方法则隐藏了这些细节,并用与任务直接相关的语言来表达程序。

2.list.h和list.c文件共同组成可重用的资源。如果需要另一个简单列表,仍可用这些头文件。

程序新知:

1.“C预处理器和C库”中的#ifndef技术对多次包含一个文件提供保护

2.“文件输入输出”fprintfgetc()函数等的使用

3.编译多文件程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值