简易链表实现
//链表储存电影列表
#define _CRT_SECURE_NO_WARNINGS
#define SIZE 20
#include <stdio.h>
#include <stdlib.h>//malloc()
#include <stdbool.h>
#include <string.h>//strchr()在字符串中查询字符
//创建一个具体的项目,含有各种属性,并抽象化
typedef struct movie {
char movie_name[SIZE];
double score;
}Item;
//创建一个节点,含有项目和指向前后节点的节点指针
typedef struct node {
Item item;
struct node* previous;
struct node* next;
}Node;
//创建一个链表,含有头尾节点及指向当前节点的node节点指针
typedef struct {
Node* head;
Node* node;
Node* end;
int node_num;
}List;
//初始化链表
bool InitList(List* plist);
bool InitList(List* plist)
{
//分配内存空间
//尝试过初始化为NULL,会报错指针为NULL无法赋值
plist->head = (Node*)malloc(sizeof(Node));
plist->node = (Node*)malloc(sizeof(Node));
plist->end = (Node*)malloc(sizeof(Node));
plist->node_num = 0;
plist->end = NULL;
//头节点的next指向尾结点,中间无节点,即链表为空
plist->head->next = plist->end;
if (plist->head->next == plist->end)
return true;
return false;
}
//判断链表是否为空
bool ListIsEmpty(List* plist);
bool ListIsEmpty(List* plist)
{
//头节点的next指向尾结点,中间无节点,即链表为空
if (plist->head->next == plist->end)
return true;
return false;
}
//判断链表是否已满
bool ListIsFull(List* plist);
bool ListIsFull(List* plist)
{
//创建一个新节点并分配内存空间
Node* ptemp;
ptemp = (Node*)malloc(sizeof(Node));
//当内存不足无法创建新节点时,说明链表已满
if (ptemp == NULL)
{
free(ptemp);//释放内存
return true;
}
free(ptemp);//释放内存
return false;
}
//增加一个新的节点
bool AddNode(List* plist, Item item);
bool AddNode(List* plist, Item item)
{
//创建一个新节点并分配内存空间
Node* pnew;
pnew = (Node*)malloc(sizeof(Node));
//不进行判断,会使程序取消对指针的引用
if (pnew == NULL)
return false;
plist->node_num++;//节点数量增加
pnew->item = item;//项目导入新节点
pnew->next = plist->end;//新节点next指向尾结点
//如何链表为空,对头节点操作
//一定要先对头节点操作
if (ListIsEmpty(plist) == true)
plist->head->next = pnew;
//如果链表非空,对当前节点操作
else if (ListIsEmpty(plist) == false)
plist->node->next = pnew;
plist->node = pnew;//记入当前节点位置
return true;
}
//释放链表内存
void FreeList(List* plist);
void FreeList(List* plist)
{
Node* psave;
while (ListIsEmpty(plist) != true)
{
psave = plist->head->next;//保存下一个节点
free(plist->head);//释放当前节点
plist->head = psave;//头节点向前推进
}
}
//用户自定义输入
bool scanf_user(Item* item);
bool scanf_user(Item* item) {
char* find;
bool flag = true;
printf("请输入电影名:\n");
//一般用fgets读取字符串
//fgets会在输入流最后自动添加停止符
//当从stdin流输入时,最后的换行符会被读入,一般用以下方式使用
if (fgets(item->movie_name, SIZE, stdin) != NULL)
{
//查找字符串中换行符转换为停止符
find = strchr(item->movie_name, '\n');
if (find)
*find = '\0';
else
//处理输入行剩余内容
while (getchar() != '\n')
continue;
}
//如果字符串为空就停止输入
if (item->movie_name[0] == '\0')
flag = false;
if (flag == true)
{
printf("请输入评分:\n");
if (scanf("%lf", &item->score) == false)
return false;
//处理输入行剩余内容
while (getchar() != '\n')
continue;
return true;
}
else
return false;
}
//用户自定义输出
void printf_user(Node* scan);
void printf_user(Node* scan)
{
//判断是不是浮点数
if ((int)scan->item.score == scan->item.score)
printf("%s\t\t%d\n", scan->item.movie_name, (int)scan->item.score);
else
printf("%s\t\t%.1lf\n", scan->item.movie_name, scan->item.score);
}
//遍历链表打印内容
bool ScanList(List* plist);
bool ScanList(List* plist)
{
Node* scan;
scan = (Node*)malloc(sizeof(Node));
printf("共%d部电影\n", plist->node_num);
printf("电影\t\t评分\n");
//遍历链表
scan = plist->head->next;
while (scan != NULL)
{
printf_user(scan);
scan = scan->next;
}
return true;
}
int main()
{
List movie;
Item item;
if (InitList(&movie))
printf("程序运行……\n");
else
{
printf("程序错误!\n");
exit(1);
}
system("pause");
system("cls");
while ((scanf_user(&item) == true))
{
if (AddNode(&movie, item) == false)
break;
}
system("cls");
if (ListIsEmpty(&movie) == true)
printf("链表为空!\n");
else
ScanList(&movie);
FreeList(&movie);
}
--------------------2022年3月23日--------------------
FreeList()修改
void FreeList(List* plist);
void FreeList(List* plist)
{
Node* psave;
while (ListIsEmpty(plist) != true)
{
psave = plist->head;//保存当前头节点
plist->head = plist->head->next;//头节点向前
free(psave);//释放节点
}
}
原来的方法其实不会向前推进头节点