单链表的c语言实现
链表是通过一组任意的存储单元来存储线性表中的数据元素,这些存储单元可以是连续的也可以是不连续的。为了建立起数据元素之间的关系,对于每个数据元素除了存放数据元素自身的信息外,还必须有包含的指示该元素直接后继元素存储位置的信息,这两部分信息组成一个结点,即每个结点都有至少包括两个域,一个域存储数据元素信息,称为数据域,另一个域存储直接后继的地址,称为指针域。
开始程序之前,先简单了解一下单链表中的一些基本概念
- 头结点:在开始结点之前的结点(可有可无),其值域不包含任何信息,也可以包含链表长度等信息。
- 开始结点:第一个元素所在的结点。
- 头指针:永远指向链表中第一个结点的位置,如果链表有头结点,头指针指向头结点;否则,头指针指向开始结点,即第一个节点。
- 带有头节点单链表头指针head指向头结点。头指针head始终不等于NULL,head->next等于NULL的时候链表为空。
- 不带头结点的单链表头指针head指向开始结点,当head等于NULL时链表为空。
- 头结点和头指针的区别:头指针是一个指针,头指针指向链表的第一个结点(如果链表有头结点,头指针指向头结点;否则,头指针指向开始结点);头结点是一个实际存在的点,它包含有数据域和指针域。头指针什么时候都应该存在,而头节点可有可无。
定义单链表结构体
typedef struct Node //定义一个结构体
{
elemtype data;
struct Node *next;
}Node;
typedef struct Node *LinkList;
初始化单链表操作
int InitList(LinkList *L) //带有头节点的单链表的初始化
{
(*L) = (LinkList)malloc(sizeof(Node)); //开辟空间
if (!L)
{
printf("分配内存失败!\n");
exit(0);
}
(*L)->next = NULL; //使头节点next为NULL,即表示空链表
return 0;
}
头插法创建单链表
void CreateListHead(LinkList *L) //头插法创建一个单链表
{
int i, n;
LinkList p; //声明一个指针p
(*L) = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL; //先建立一个带头节点的空链表
printf("请输入您要插入元素的个数:");
scanf("%d", &n);
printf("请输入你要插入的元素值(用空格隔开):");
for (i = 0; i < n; i++)
{
p = (LinkList)malloc(sizeof(Node)); //生成新节点
scanf("%d", &p->data);
p->next = (*L)->next;
(*L)->next = p; //插入到表头
}
}
头插法算法思路
- 声明一指针p和计数器变量i及要输入元素的个数n
- 初始化一空链表L
- 让L的头节点的指针指向NULL,即建立一个带头节点的单链表
- 输入要插入元素的个数及各元素值
- 循环
- 生成一个新节点赋值给p
- 输入元素值p->data
- 将p插入到头节点和前一新节点之间
尾插法创建单链表
void CreateListTail(LinkList *L) //尾插法创建一个单链表
{
int i, n;
LinkList p,r;
(*L) = (LinkList)malloc(sizeof(Node));
r = *L; //r为指向尾部的节点的指针
printf("请输入您要插入元素的个数:");
scanf("%d", &n);
printf("请输入你要插入的元素值(用空格隔开):");
for (i = 0; i < n; i++)
{
p = (LinkList)malloc(sizeof(Node)); //生成新节点
scanf("%d", &p->data);
r->next = p; //将表尾终端节点的指针指向新节点
r = p; //将当前的新节点定义为表尾终端节点
}
r->next = NULL; //表示单链表结束
}
尾插法和头插法大同小异,只是头插法使倒序排列,尾插法是正序排列,尾插法也符合我们正常的先来后到的思维
计算单链表的长度
int LengthList(LinkList *L) //计算链表长度
{
int length = 0; //计算链表长度
LinkList p;
p = (*L)->next; //使p指向链表的第一个节点
while (p)
{
length++;
p = p->next;
}
return length; //返回链表长度
}
获取单链表中元素
int GetElem(LinkList L, int i, elemtype *e) //用e返回L中第i个元素值
{
int j = 1;
LinkList p;
p = L->next; //使p指向链表的第一个节点
while (p && j < i) //p不为NULL并且j < i 时循环
{
p = p->next;
++j;
}
if (!p || j > i)
{
printf("查询不到该元素!\n");
return 0;
}
*e = p->data; //将查到的数据用e返回
return 0;
}
获得链表第i个数据的算法思路:
- 声明一个指针p指向链表中第一个节点,初始化j从1开始
- 当 j < i 时,就遍历链表,让p的指针向后移动,不断指向下一节点,j累加1
- 当到链表尾p为空,则说明第i个节点不存在
- 否则查找成功,返回节点p的数据
新元素插入单链表
int InsertList(LinkList *L, int i, elemtype e) //在L中第i个位置插入元素e
{
LinkList p, s;
int j = 1;
p = *L; //使p指向头节点
while (p && j < i)
{
p = p->next;
++j;
}
if (!p || j > i)
{
printf("插入元素失败!\n");
return 0;
}
s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next; //将p的后继节点赋值给s的后继
p->next = s; //将s赋值给p的后继
return 0;
}
单链表第i个数据插入节点的算法思路
- 声明一指针p指向链表头节点,初始化j从1开始
- 当 j < i 时,就遍历链表,让p的指针向后移动,不断指向下一节点,j 累加1
- 若到链表末尾p为空,则说明第i个节点不存在
- 否则查找成功,在系统中生成一个空节点s
- 将数据元素e赋值给s->data
- 单链表的插入标准语句
s->next=p->next;p->next = s
- 返回0
删除链表中某元素
int DeleteList(LinkList *L, int i, elemtype *e) //删除L中第i个元素,并用e返回其值
{
LinkList p, q;
int j = 1;
p = *L;
while (p->next && j < i) //遍历寻找第i - 1 个节点
{
p = p->next;
++j;
}
if (!(p->next) || j > i)
{
printf("删除元素失败!\n");
return 0;
}
q = p->next;
p->next = q->next; //将q的后继赋值给p的后继
*e = q->data; //将q节点中的数据给e*
free(q); //释放q节点
return 0;
}
单链表第i个数据删除节点的算法思路:
- 声明一指针p指向链表头节点,初始化j从1开始
- 当 j < 1 时,就遍历链表,让p的指针向后移动,不断指向下一个节点,j 累加1
- 若到链表末尾p为空,则说明第i个节点不存在
- 否则查找成功,将要删除的节点p->next赋值给q
- 单链表的删除标准语句p->next = q->next;
- 将q节点中的数据赋值给e,作为返回
- 释放q节点
- 返回0
单链表的整表删除
int ClearList(LinkList *L) //单链表的整表删除
{
LinkList p, q;
p = (*L)->next;
while (p)
{
q = p->next;
free(p); //循环,逐个释放各个节点
p = q;
}
(*L)->next = NULL; //将头节点的next置空
return 0;
}
打印出整个单链表
void ShowList(LinkList *L) //打印整个链表
{
LinkList p;
p = (*L)->next;
if (p == NULL)
{
printf("这是一个空链表!\n");
}
printf("单链表");
while (p)
{
printf(" -> %d", p->data);
p = p->next;
}
printf("\n");
}
到此,单链表的基本操作已经完成,下面附上源码
源码:
#include<stdio.h>
#include<stdlib.h>
typedef int elemtype;
typedef struct Node //定义一个结构体
{
elemtype data;
struct Node *next;
}Node;
typedef struct Node *LinkList;
int InitList(LinkList *L) //带有头节点的单链表的初始化
{
(*L) = (LinkList)malloc(sizeof(Node));
if (!L)
{
printf("分配内存失败!\n");
exit(0);
}
(*L)->next = NULL;
return 0;
}
void CreateListHead(LinkList *L) //头插法创建一个单链表,n为要插入的元素个数
{
int i, n;
LinkList p;
(*L) = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
printf("请输入您要插入元素的个数:");
scanf("%d", &n);
printf("请输入你要插入的元素值(用空格隔开):");
for (i = 0; i < n; i++)
{
p = (LinkList)malloc(sizeof(Node));
scanf("%d", &p->data);
p->next = (*L)->next;
(*L)->next = p;
}
}
void CreateListTail(LinkList *L) //尾插法创建一个单链表,n为要插入的元素个数
{
int i, n;
LinkList p,r;
(*L) = (LinkList)malloc(sizeof(Node));
r = *L;
printf("请输入您要插入元素的个数:");
scanf("%d", &n);
printf("请输入你要插入的元素值(用空格隔开):");
for (i = 0; i < n; i++)
{
p = (LinkList)malloc(sizeof(Node));
scanf("%d", &p->data);
r->next = p;
r = p;
}
r->next = NULL;
}
int LengthList(LinkList *L) //计算链表长度
{
int length = 0;
LinkList p;
p = (*L)->next;
while (p)
{
length++;
p = p->next;
}
return length;
}
int GetElem(LinkList L, int i, elemtype *e) //用e返回L中第i个元素值
{
int j = 1;
LinkList p;
p = L->next;
while (p && j < i)
{
p = p->next;
++j;
}
if (!p || j > i)
{
printf("查询不到该元素!\n");
return 0;
}
*e = p->data;
return 0;
}
int InsertList(LinkList *L, int i, elemtype e) //在L中第i个位置插入元素e
{
LinkList p, s;
int j = 1;
p = *L;
while (p && j < i)
{
p = p->next;
++j;
}
if (!p || j > i)
{
printf("插入元素失败!\n");
return 0;
}
s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next;
p->next = s;
return 0;
}
int DeleteList(LinkList *L, int i, elemtype *e) //删除L中第i个元素,并用e返回其值
{
LinkList p, q;
int j = 1;
p = *L;
while (p->next && j < i)
{
p = p->next;
++j;
}
if (!(p->next) || j > i)
{
printf("删除元素失败!\n");
return 0;
}
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return 0;
}
int ClearList(LinkList *L) //单链表的整表删除
{
LinkList p, q;
p = (*L)->next;
while (p)
{
q = p->next;
free(p);
p = q;
}
(*L)->next = NULL;
return 0;
}
void ShowList(LinkList *L) //打印整个链表
{
LinkList p;
p = (*L)->next;
if (p == NULL)
{
printf("这是一个空链表!\n");
}
printf("单链表");
while (p)
{
printf(" -> %d", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
LinkList L;
InitList(&L);
int k,i;
elemtype m ;
CreateListHead(&L);
ShowList(&L);
printf("单链表的长度为%d\n", LengthList(&L));
CreateListTail(&L);
ShowList(&L);
printf("单链表的长度为%d\n",LengthList(&L));
GetElem(L, 5, &m);
printf("得到的元素值为:%d\n", m);
InsertList(&L, 4, 25);
printf("插入元素后的");
ShowList(&L);
DeleteList(&L, 3, &m);
printf("删除元素后的");
ShowList(&L);
printf("删除的元素值为:%d\n", m);
ClearList(&L);
system("pause");
return 0;
}