文章目录
一、list.h
1、引用库函数
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
2、枚举选择项
enum Option
{
EXIT,
push_back,
push_front,
show_list,
pop_back,
pop_front,
insert_val,
find,
length,
delete_val,
sort,
resver,
clear,
destroy
};
3、用结构体构造单链表
a、单链表的构造
typedef struct Node
{
ElemType data;//数据域
struct Node* next;指针域
}Node;
b、对单链表的管理
typedef struct List
{
Node* first;//让其始终指向头结点
Node* last;//让其始终指向尾结点
int size;//记录结点个数
}List;
4、函数声明
void InitList(List* list);
void PushBack(List* list, ElemType x);
void PushFront(List* list, ElemType x);
void ShowList(List* list);
void PopBack(List* list);
void PopFront(List* list);
void InsertPos(List* list, ElemType x);
Node* Find(List* list, ElemType key);
void Length(List* list);
void DeletePos(List* list, ElemType val);
void Sort(List* list);
void Resver(List* list);
void Clear(List* list);
void Destroy(List* list);
5、其他
#define ElemType int//进行宏定义,即:凡是用到ElemType的地方都用int代替
二、Main_list.c
1、定义单链表
List mylist;//定义一个单链表
2、选择系统
void menu()
{
puts("**********************************************************");
puts("*** 1、尾插 2、头插 3、显示 4、尾删 ***");
puts("*** 5、头删 6、按位置插入 7、查找 8、求长度 ***");
puts("*** 9、按位置删除 10、排序 11、逆置 12、清除 ***");
puts("*** 13、销毁 0、退出 ***");
puts("**********************************************************");
printf("请选择:> ");
}
void select()
{
int input = 0;
ElemType Item;
while (1)
{
system("cls");
menu();
scanf("%d", &input);
switch (input)
{
case push_back:printf("请输入要插入的数据(-1)结束:> ");
while (scanf("%d", &Item), Item != -1)
{
PushBack(&mylist, Item);
}
break;
case push_front:printf("请输入要插入的数据(-1)结束:> ");
while (scanf("%d", &Item), Item != -1)
{
PushFront(&mylist, Item);
}
break;
case show_list:ShowList(&mylist);
break;
case pop_back:PopBack(&mylist);
break;
case pop_front:PopFront(&mylist);
break;
case insert_pos:printf("请输入要插入的数据;> ");
scanf("%d", &Item);
InsertPos(&mylist, Item);
break;
case find:printf("请输入你要查找的数据;> ");
scanf("%d", &Item);
Find(&mylist,Item);
break;
case length:Length(&mylist);
break;
case delete_pos:printf("请输入要删除的数据;> ");
scanf("%d", &Item);
DeletePos(&mylist, Item);
break;
case sort:Sort(&mylist);
break;
case resver:Resver(&mylist);
break;
case clear:Clear(&mylist);
break;
case destroy:Destroy(&mylist);
break;
case EXIT:puts("即将退出!"); system("pause"); Destroy(&mylist); exit(0);
break;
default:puts("选择有误,请重试!"); system("pause");
break;
}
}
}
三、Fun_list.c
1、初始化
建立一个头结点,是first指针、last指针都指向头结点!
void InitList(List* list)
{
list->first = list->last = (Node*)malloc(sizeof(Node));
assert(list->first != NULL);
list->first->next = NULL;
list->size = 0;
}
2、尾插
只需更改last的指向即可!
void PushBack(List* list, ElemType x)
{
//给插入的数据开辟一个空间
Node* s = (Node*)malloc(sizeof(Node));//申请一个插入结点的空间
assert(s != NULL);
s->data = x;
s->next = NULL;
//尾插
list->last->next = s;//连接前一个结点
list->last = s;//让last始终指向最后一个结点
list->size++;
}
3、头插
注意:若为空表,则头插需要改变尾指针的指向!!
void PushFront(List* list, ElemType x)
{
Node* s = (Node*)malloc(sizeof(Node));//申请一个插入结点的空间
assert(s != NULL);
s->data = x;
s->next = list->first->next;
list->first->next = s;
if (list->size == 0)//如果表中无结点,则插入需改尾指针last的指向
{
list->last = s;
}
list->size++;
}
4、显示
void ShowList(List* list)
{
if (list->size == 0)
{
puts("链表为空!");
system("pause");
return;
}
Node* p = list->first->next;//将第一个结点的值赋给p
while (p != NULL)
{
printf("%d->", p->data);
p = p->next;
}
printf("NULL\n");
system("pause");
}
5、尾删
操作方法:只需将尾指针的指向前一个结点,释放掉最后一个结点即可!
void PopBack(List* list)
{
if (list->size==0)
{
puts("链表为空,无法删除!");
system("pause");
return;
}
Node* p = list->first;
while (p->next != list->last)//寻找尾结点的前驱
p = p->next;
free(list->last);//找到后将其释放
list->last = p;//让尾指针指向前驱
list->last->next = NULL;
list->size--;
}
6、头删
操作步骤:将头结点的指针域指向它的下下个结点的地址,再释放掉头结点的下一个结点!
注意:链表只有头结点和尾结点的情况(即:只有两个结点)——此时应改变尾指针的指向!
void PopFront(List* list)
{
if (list->size == 0)
{
puts("链表为空,无法删除!");
system("pause");
return;
}
Node* p = list->first->next;
list->first->next = p->next;//让头结点的指针域指向它的下下个结点
free(p);
p = NULL;
if (list->size == 1)//判断是否删除的是最后一个结点
{
list->last = list->first;
}
list->size--;
}
7、按位置插入
a、查找删除位置的前一个结点
Node* query(List* list,int i)
{
int n = 0;
Node* p = list->first;
for (n = 1; n <= i; n++)
{
p = p->next;
}
return p;
}
b、插入操作
void InsertPos(List* list, ElemType x)
{
int pos;
Node* node = (Node*)malloc(sizeof(Node));//申请一个插入结点的空间
assert(node != NULL);
node->data = x;
printf("请输入你要插入的位置:> ");
scanf("%d", &pos);
//判断插入位置的合法性
//pos小于1或者pos大于了链表长度,则不合法
//但要排出pos=1并且链表为空时的情况
if (pos == 1 && list->size==0)
{
node->next = list->first->next;
list->first->next = node;
list->last = node;
list->size++;
return;
}
if (pos<1 || pos>list->size)
{
puts("插入位置不合法!");
system("pause");
return;
}
Node* p = query(list,pos - 1);
node->next = p->next;
p->next = node;
list->size++;
}
8、查找
void Find(List* list, ElemType key)
{
Node* p = list->first->next;
while (p != NULL && p->data != key)//两者顺序不能颠倒
{
p = p->next;
}
if (p == NULL)
{
puts("要查找的数据在链表中不存在!");
system("pause");
return;
}
printf("查找结果%d存在\n", p->data);
system("pause");
}
9、求长度
void Length(List* list)
{
printf("链表长度为:%d\n", list->size);
system("pause");
}
10、按位置删除
此处我们用另一种方法实现删除!
void DeletePos(List* list, ElemType val)
{
Node* p = Find(list, val);
if (p == NULL)
{
puts("无法删除!");
system("pause");
return;
}
//此处不再寻找删除位置的前驱结点
//采用把删除结点的下一个结点的数据复制到删除结点中
//再释放掉删除结点的下一结点
if (p == list->last)//排出掉删除的是最后一个结点的情况
{
PopBack(list);
}
else
{
Node* q = p->next;//保存删除位置的下一个结点地址
p->data = q->data;
p->next = q->next;
free(q);
q = NULL;
list->size--;
}
}
11、排序
void Sort(List* list)
{
if (list->size == 0 || list->size == 1)
return;
Node* s = list->first->next;
Node* q = s->next;
//断开链表
list->last = s;
list->last->next = NULL;
//排序
while (q != NULL)
{
s = q;
q = q->next;
Node* p = list->first;
while (p->next != NULL && p->next->data < s->data)
{
p = p->next;
}
if (p->next == NULL)
{
list->last = s;
}
s->next = p->next;
p->next = s;
}
}
12、逆置
void Resver(List* list)
{
if (list->size == 0 || list->size == 1)
return;
Node* s = list->first->next;
Node* q = s->next;
//断开链表
list->last = s;
list->last->next = NULL;
while (q != NULL)
{
s = q;
q = q->next;
s->next = list->first->next;
list->first->next = s;
}
}
13、清除
void Clear(List* list)
{
if (list->size == 0)
return;
Node* p = list->first->next;
while (p != NULL)
{
list->first->next = p->next;
free(p);
p = list->first->next;
}
list->last = list->first;
list->size = 0;
}
14、销毁
void Destroy(List* list)
{
Clear(list);
free(list->first);
list->first = list->last = NULL;
}
15、改进
a、申请结点的改进
Node* BuyNode(ElemType x)
{
Node* s = (Node*)malloc(sizeof(Node));
assert(s != NULL);
s->data = x;
s->next = NULL;
return s;
}
b、插入操作的改进
It begin(List* list)
{
return list->first->next;
}
It end(List* list)
{
return list->last->next;
}
void Insert(List* list, It pos, ElemType x)
{
Node* p = list->first;
while (p->next != pos)
{
p = p->next;
}
Node* s = BuyNode(x);
s->next = p->next;
p->next = s;
if (pos == NULL)
{
list->last = s;
}
list->size++;
}
c、头文件中需要添加的声明
Node* BuyNode(ElemType x);
typedef Node* It;
It begin(List* list);
It end(List* list);
void Insert(List* list, It pos, ElemType x);
d、查找方法的改进
Node* Find(List* list, ElemType key)//可更改返回值为查找元素的前驱结点——自行实现
{
Node* p = list->first->next;
if (p->data == key)
{
printf("查找结果p的前驱结点数据为头结点\n");
system("pause");
return p;
}
while (p != NULL && p->data != key)//两者顺序不能颠倒
{
if (p->next->data == key)
{
printf("查找结果p的前驱结点数据为%d\n", p->data);
system("pause");
return p;
}
p = p->next;
}
if (p == NULL)
{
puts("要查找的数据在链表中不存在!");
system("pause");
return p;
}
return p;
}