链表的基本操作包括建立(批量存入数据)、打印(输出所有数据)、删除(在批量数据中删除指定数据)、插入(在批量数据中添加一个数据)等。
1、链表的建立
链表的建立就是从一个空链表开始,一个9一个地添加新结点,直至所有数据都加入该链表。
链表真正使用时,结点是动态产生的。当出现一个需要处理的数据时,首先动态申请一个结点空间,然后对结点的数据域进行赋值,再对结点的指针域进行处理,使该结点链入到整个单链表中。
按照新结点加入位置的不同,链表的建立大致有以下几种方法:
- 前插法:新结点每次都插入到链表的最开头,作为新链表的第一个结点;
- 尾插法:新结点每次都插入到链表的最后面,作为新链表的最后一个结点;
- 序插法:新结点插入后保证结点域数据的有序性,该法需经搜索确定插入位置;
- 定位法:新结点插入到链表中制定的位置。
这里主要介绍尾插法的基本思想:
(1)定义两个指针分别指向链表的第一个和最后一个结点,假设这两个指针名字为head 和tail。
(2)初始化链表,即“head=tail=NULL;”让两个工作指针均不指向任何地方。
Node* head, * tail; //head、tail分别指向链表的头结点和尾结点
head = tail = NULL; //初始化链表:空链表
(3)通过工作指针p申请一个动态结点空间,然后将数据赋值给动态结点的数据域,指针域及时赋值为空。
p = (Node*)malloc(sizeof(Node)); //动态申请一块结点的内存用于存放数据
p->data = num; //将输入的值num存放入新结点的数据域
p->next = NULL; //新结点的指针域及时赋为空值
(4)生成一个新结点p之后,head指针要根据原来链的情况进行不同的处理:如果原来是空链,则head等于p;如果原来非空,则head不需要做任何处理。然后将p所指向的结点,链到tail所指向的结点后面,体现“尾插”思想。最后将p赋值给tail,保证tail始终指向当前链表的最后一个结点处。
if (NULL == head) //如果原来链表为空
head = p; //将p赋值给head,p是刚申请的第一个结点
else //如果原来链表非空
tail->next = p; //将新结点链入尾部成为新的最后结点
tail = p;
如果原来链表为空:
如果原来链表非空:
(5)重复进行(3)、(4)两个步骤,直至结束。
下面的示例给出了用尾插法建立链表,再对该链表进行遍历输出所有的元素,最后利用遍历思想释放所有结点动态空间的完整过程。
#include<stdio.h>
#include<malloc.h>
typedef struct Node //定义链表结点的类型
{
int data; //数据域
struct Node* next; //指针域
}Node; //定义类型的别名为Node
Node* Create(); //创建一个新的链表
void Print(Node* head);
void Release(Node* head);
int main()
{
Node* head; //定义头指针head
head = Create(); //创建一个新链表,返回头指针赋值给head
Print(head); //链表的遍历输出每个元素的值
Release(head); //释放链表每个结点的存储空间
return 0;
}
Node* Create()
{
Node* head, * tail, * p; //head、tail分别指向链表的头结点和尾结点
int num;
head = tail = NULL; //链表初始化:空链表
printf("请输入一批数据,以“-9999”结尾:\n");
scanf_s("%d", &num);
while (num != -9999)
{
p = (Node*)malloc(sizeof(Node)); //动态申请一块结点的内存用于存放数据
p->data = num; //将输入的值存放入新结点的数据域
p->next = NULL; //新结点的指针域及时赋为空值
if (NULL == head) //如果原来链表为空
head = p; //将p赋值给head,p是刚申请的第一个结点
else //如果原来链表非空
tail->next = p; //将新结点链入尾部成为新的最后结点
tail = p;
scanf_s("%d", &num);
}
return head;
}
void Print(Node* head)
{
Node* p; //定义工作指针P
p = head; //p从头指针开始
if (NULL == head) //如果链表为空则输出提示信息
{
printf("链表为空!\n");
}
else
{
printf("链表如下:\n");
while (p != NULL) //用p来控制循环,p为空时指针停止
{
printf("%4d", p->data);
p = p->next;
}
}
printf("\n");
}
void Release(Node* head)
{
Node* p1, * p2;
p1 = head;
while (p1 != NULL) //p1用来控制循环,
{
p2 = p1; //p2指向当前删除结点处
p1 = p1->next; //p1指向链表下一个结点位置处
free(p2); //通过p2释放空间
}
printf("链表释放内存成功!\n");
}
运行程序,屏幕上输入数据,结果显示: