链表的基本操作
-
在说链表之前,我们先说说顺序存储。其中我们最熟悉的一种顺序存储的数据结构就是数组,当我们想要给数组中插入一个元素时,为保证顺序以及其他元素不丢失,我们需要在插入元素后,将后面的元素整体后移。所以容易看出这样有着这两个弊端:第一:我们所需要移动的元素有很多时,会浪费算力。第二:我们必须为数组开足够多的空间,否则会存在溢出风险。
为了避免这两个弊端,我们引入链式存储——链表。
什么是链表?
简单来说,链表的利用结构体,额外开辟出一份内存空间去作指针,它总是指向下一个结点,一个个结点通过指针相互串联,这就形成了我们的链表。
其中DATA数据元素(数据域),可以是int类型或char类型,甚至可以是结构体。NEXT为一个指针通常是用来指向下一个结点,链表的尾部NEXT指向NULL,因为它没有可以指向的空间了。
对于一个单链表的结点定义:
//定义结点类型
typedef struct Node
{
int DATA;//数据域
struct Node* NEXT;//指针域
}Node,* pointnode;//Node表示结点的类型,pointnode表示指向Node结点类型的指针类型
1.对链表进行初始化:
pointnode Initialize()
{
Node* H=(Node*)malloc(sizeof(Node)); //开辟空间
if(H==NULL) //判断是否开辟成功
{
printf("开辟失败!");//开辟失败的提示
exit(0); // 开辟失败结束程序(根据情况看是否添加)
}
H->NEXT=NULL; //指针指向NULL
}
2.创建单链表:
<1>头插法
从一个空表开始,生成新结点,并将数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头即头结点之后。
pointnode listofhead()
{
Node* H = (Node*)malloc(sizeof(Node));//开辟一个头空间
H -> NEXT= NULL; //初始化为空
int x;
while (scanf("%d", &x) != EOF) //输入数据,当输入空的时候停止(在Windows下:Ctrl+Z)
{
Node* p = (Node*)malloc(sizeof(Node));
p->DATA = x; //赋值给数据域
p->NEXT = H->NEXT; //将节点插到表头
H->NEXT = p;
}
return H;
}
<2>尾插法
将新结点逐个插入到当前链表的表尾上,增加一个尾指针, 使其始终指向当前链表的尾结点。
pointnode listofend()
{
Node* H = (Node*)malloc(sizeof(Node)); //开辟头空间
H->NEXT = NULL; //初始化
int x;
Node* l; //定义为尾指针
l = H; // 尾指针开始指向头,始终指向尾。
while (scanf("%d", &x) != EOF)
{
Node* p = (Node*)malloc(sizeof(Node));
p->DATA = x;
l->NEXT = p; //将结点插到表头
l = p;
}
l->NEXT = NULL;
return H;
}
注意:头插法的顺序是逆序的:表头->[n]->···->[2]->[1]->NULL
尾插法是正序的:表头->[1]->[2]->····[n]->NULL
3.链表的遍历
void listoftravel(pointnode H)
{
Node* p = H->NEXT;
int i = 1;
while (p)
{
printf("第%d个数据是%d\n", i++, p->DATA);
p = p->NEXT;
}
}
4.链表的插入
//链表的插入
pointnode datainlist(pointnode H,int i,int x)
{
Node* preve = H;
int seek;
for (seek = 1; seek < i; seek++)//寻找元素位置
{
preve = preve->NEXT;
}
Node* p = (Node*)malloc(sizeof(Node));
p->DATA = x;
p->NEXT = preve->NEXT;
preve->NEXT = p;
return H;
}
4.链表的修改
//链表的修改
pointnode moddata(pointnode H,int x,int t)
{
Node* p = H->NEXT;
while (p)
{
if (p->DATA == x)
{
p->DATA = t;
}
p = p->NEXT;
}
return H;
}
5.链表的删除
//链表的删除
pointnode freedata(pointnode H,int x)
{
Node* p;
Node* preve;//前驱结点
p = H->NEXT;
while (p->DATA != x)//查找元素
{
preve = p;
p = p ->NEXT;
}
preve->NEXT = p->NEXT;
free(p); //删除操作
return H;
}
完整代码:
#include<stdio.h>
#include<stdlib.h>
//定义结点类型
typedef struct Node
{
int DATA;//数据域
struct Node* NEXT;//指针域
}Node, * pointnode;
//Node表示结点的类型,pointnode表示指向Node结点类型的指针类型
//链表的初始化
pointnode Initialize()
{
Node* H = (Node*)malloc(sizeof(Node)); //开辟空间
if (H == NULL) //判断是否开辟成功
{
printf("开辟失败!");//开辟失败的提示
exit(0); // 开辟失败结束程序(根据情况看是否添加)
}
H->NEXT = NULL; //指针指向NULL
}
//头插法建立链表
pointnode listofhead()
{
Node* H = (Node*)malloc(sizeof(Node));//开辟一个头空间
H = NULL; //初始化为空
int x;
while (scanf("%d", &x) != EOF) //输入数据,当输入空的时候停止(在Windows下:Ctrl+Z)
{
Node* p = (Node*)malloc(sizeof(Node));
p->DATA = x; //赋值给数据域
p->NEXT = H->NEXT; //将节点插到表头
H->NEXT = p;
}
return H;
}
//尾插法
pointnode listofend()
{
Node* H = (Node*)malloc(sizeof(Node)); //开辟头空间
H->NEXT = NULL; //初始化
int x;
Node* l; //定义为尾指针
l = H; // 尾指针开始指向头,始终指向尾。
while (scanf("%d", &x) != EOF)
{
Node* p = (Node*)malloc(sizeof(Node));
p->DATA = x;
l->NEXT = p; //将结点插到表头
l = p;
}
l->NEXT = NULL;
return H;
}
//遍历链表
void listoftravel(pointnode H)
{
Node* p = H->NEXT;
int i = 1;
while (p)
{
printf("第%d个数据是%d\n", i++, p->DATA);
p = p->NEXT;
}
}
//链表的插入
pointnode datainlist(pointnode H,int i,int x)
{
Node* preve = H;
int seek;
for (seek = 1; seek < i; seek++)//寻找元素位置
{
preve = preve->NEXT;
}
Node* p = (Node*)malloc(sizeof(Node));
p->DATA = x;
p->NEXT = preve->NEXT;
preve->NEXT = p;
return H;
}
//链表的修改
pointnode moddata(pointnode H,int x,int t)
{
Node* p = H->NEXT;
while (p)
{
if (p->DATA == x)
{
p->DATA = t;
}
p = p->NEXT;
}
return H;
}
//链表的删除
pointnode freedata(pointnode H,int x)
{
Node* p;
Node* preve;//前驱结点
p = H->NEXT;
while (p->DATA != x)//查找元素
{
preve = p;
p = p ->NEXT;
}
preve->NEXT = p->NEXT;
free(p); //删除操作
return H;
}
int main()
{
pointnode list;
Initialize();
list = listofend();
//list = listofhead();
listoftravel(list);
//链表的修改
int x;
int t;
printf("你想修改的数据是:");
scanf("%d", &x);
printf("你想把他改为:");
scanf("%d", &t);
moddata(list, x, t);
listoftravel(list);
//链表的插入
int i;
printf("你想在哪个位置插入数据:");
scanf("%d", &i);
printf("你想插入的数据是:");
scanf("%d", &x);
datainlist(list, i, x);
listoftravel(list);
//链表的删除
printf("你想删除的数据是:");
scanf("%d", &x);
freedata(list, x);
listoftravel(list);
return 0;
}