线性表的链式存储结构:定义、单链表存储结构、给链表头结点分配空间、初始化链表数据、输出链表、在某个位置上插入数据、头插法、尾插法、删除某个位置上的数据、删除某个数据、删除整个链表计算链表的长度
1、线性表链式存储结构定义
1.1特点:用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。
1.2为了表示每个数据ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储本身的信息之外,还需要存储一个指示其直接后继的信息(即直接后继的存储位置)。我们吧存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称做指针或链。这两部分信息组成数据元素ai的存储映像,称为结点(Node)。
1.3链表中第一个结点的存储位置叫做头指针;线性表的最后一个结点指针为空(通常用符号NULL或“^”表示)。
1.4在单链表的第一个结点前附设一个结点,称为头结点。
2、头指针与头结点的异同
2.1头指针
(1)头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;
(2)头指针具有标识作用,所以常用头指针冠以链表的名字;
(3)无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
2.2头结点
(1)头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可以存放链表的长度);
(2)有了头结点,对在第一个元素结点前插入结点和删除第一结点,其操作与其它结点的操作就统一了;
(3)头结点不一定是链表必须要素。
3、功能实现代码
(1)线性表的单链表存储结构
typedef struct Node
{/*线性表的单链表存储结构*/
ElenType data;
struct Node *next;
}Node;
typedef struct Node *LinkList;/*定义指针*/
(2)线性表的初始化:分配空间
L为二级指针,通过此操作来给头结点分配空间。
void Initialize(LinkList *L)
{/*初始化链表指针:分配空间*/
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
}
(3)输出链表中的数据
A. P指向头结点之后的存储数据的结点p = L->next;
B. 判断头结点的下一个结点是否为空,若为空则输出“链表为空!”的信息;
C. 若不为空,则遍历输出数据,printf("%d ", p->data); p = p->next;直到结点为空时退出循环。
void Display(LinkList L)
{/*输出链表中的数据*/
LinkList p = L->next;
if (!p)
printf("链表为空!\n");
else
{
while (p)
{
printf("%d ", p->data);
p = p->next;
}
putchar('\n');
}
}
(4)初始化链表:输入初始化的数据
A. P指向链表头结点L ,p = L;
B. 输入需要创建的数据个数;
C. 给结点q分配空间q = (LinkList)malloc(sizeof(Node));
D. 输入数据,然后结点p的指针指向结点q,结点p再更新指向结点q,p->next = q; p = p->next;
E. 循环创建结点,直到j>i时退出循环;
F. 将最后一个结点的指针置空p->next = NULL;
void create(LinkList L)
{/*初始化链表:输入初始化的数据*/
int i,j=1;
LinkList p, q;
p = L;
printf("请输入需要初始化的数据个数:");
scanf_s("%d", &i);
while (j <= i)
{
q = (LinkList)malloc(sizeof(Node));
printf("请输入第%d个数据:",j);
scanf_s("%d", &q->data);
p->next = q;
p = p->next;
j++;
}
p->next = NULL;
}
(5)插入数据:在某个位置插入数据
A. 指针p指向链表头结点,p = L;
B. 遍历寻找需要插入位置的前一个位置p = p->next;,当查找到该位置或者不存在该位置时退出循环;
C. 如果插入位置之前的位置为空或者不存在该位置,则返回ERROR;
D. 否则给结点q分配空间,输入数据,q = (LinkList)malloc(sizeof(Node)); q->data = e;
E. 将结点q的指针置指向插入位置的那一个结点q->next = p->next;使得结点q取代这一个位置;
F. 插入位置前一个结点的指针指向结点q,p->next = q;
int InsertionLocation(LinkList L, int i,ElenType e)
{/*插入数据:在某个位置插入数据*/
int j=1;
LinkList q, p;
p = L;
while (p&&j < i)
{/*寻找需要插入的位置*/
p = p->next;
++j;
}
if (!p || j > i)
return ERROR;
q = (LinkList)malloc(sizeof(Node));
q->data = e;
q->next = p->next;
p->next = q;
return OK;
}
(6)插入数据:头插法
A. 指针p指向链表头结点L;
B. 创建新的结点q = (LinkList)malloc(sizeof(Node));
C. 将插入数据赋予新的结点q->data = e;
D. 新结点的指针指向头结点之后的第一个结点q->next = p->next;
E. 头结点指向新的结点p->next = q;
void InsertionHead(LinkList L,ElenType e)
{/*插入数据:头插法*/
LinkList p = L, q;
q = (LinkList)malloc(sizeof(Node));
q->data = e;
q->next = p->next;
p->next = q;
}
(7)插入数据:尾插法
A. 指针p指向链表头结点L;
B. 遍历结点p的下一个结点是否为空p = p->next;当为空时退出循环;
C. 创建新的结点q = (LinkList)malloc(sizeof(Node));
D. 将插入数据赋予新的结点q->data = e;
E. 将q的指针置空q->next = NULL;
F. 最后一个结点的指针指向新节点q,p->next = q;
void InsertionTail(LinkList L, ElenType e)
{/*插入数据:尾插法*/
LinkList p=L, q;
while (p->next)
p = p->next;
q = (LinkList)malloc(sizeof(Node));
q->data = e;
q->next = NULL;
p->next = q;
}
(8)删除数据:删除某个位置上的数据
A. 指针p指向链表头结点L;
B. 遍历寻找需要删除的结点之前的那个结点p = p->next;直到找到该结点或者不存在这个结点时退出循环;
C. 如果不存在删除节点则返回ERROR;
D. 否则,结点q指向待删除的结点q = p->next;
E. 待删除结点前面的结点的指针指向待删除结点后面的那一个结点p->next = q->next;
F. 释放待删除结点的空间free(q);
int DeleteLocation(LinkList *L, int i)
{/*删除某个位置上的数据*/
LinkList q, p = *L;
int j = 1;
while (j++ < i && p)
p = p->next;
if (j > i + 1 || !p)
return ERROR;
q = p->next;
p->next = q->next;
free(q);
return OK;
}
(9)删除数据:删除某个数据——方式一
int DeleteDataOne(LinkList L, ElenType e)
{/*删除某个数据*/
LinkList p=L , q;
while (p->next)
{/*结点不为空则运行*/
if (p->next->data == e)
{/*判断下一个结点是否符合要求*/
q = p->next;/*q继承下一个符合要求的结点*/
p->next = q->next;/*p指向下下个结点*/
free(q);/*释放q的空间*/
return OK;
}
p = p->next;/*若没有查找到符合要求结点,则结点后移*/
}
printf("不存在该数据!\n");
return ERROR;
}
(9)删除数据:删除某个数据——方式二
int DeleteDataTwo(LinkList L, ElenType e)
{/*删除某个数据*/
LinkList p = L, q = L->next;
while (q)
{
if (q->data == e)
{
p->next = q->next;
free(q);
return OK;
}
p = q;
q = q->next;
}
printf("不存在该数据!\n");
return ERROR;
}
(10)删除整个链表
int ClearList(LinkList *L)
{/*删除整个链表*/
LinkList p, q;
p = (*L)->next;
while (p)
{
q = p->next;
free(p);
p = q;
}
(*L)->next = NULL;
return OK;
}
(11)计算链表的长度
int Length(LinkList L)
{/*计算链表的长度*/
LinkList p = L;
int length = 0;;
while (p->next)
{
length++;
p = p->next;
}
return length;
}
(12)完整测试代码(编译环境Visual Studio 2017)
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef int ElenType;/*线性表中存储的数据类型*/
typedef struct Node
{/*线性表的单链表存储结构*/
ElenType data;
struct Node *next;
}Node;
typedef struct Node *LinkList;/*定义指针*/
void Initialize(LinkList *L)
{/*初始化链表指针:分配空间*/
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
}
void Display(LinkList L)
{/*输出链表中的数据*/
LinkList p = L->next;
if (!p)
printf("链表为空!\n");
else
{
while (p)
{
printf("%d ", p->data);
p = p->next;
}
putchar('\n');
}
}
void create(LinkList L)
{/*初始化链表:输入初始化的数据*/
int i,j=1;
LinkList p, q;
p = L;
printf("请输入需要初始化的数据个数:");
scanf_s("%d", &i);
while (j <= i)
{
q = (LinkList)malloc(sizeof(Node));
printf("请输入第%d个数据:",j);
scanf_s("%d", &q->data);
p->next = q;
p = p->next;
j++;
}
p->next = NULL;
}
int InsertionLocation(LinkList L, int i,ElenType e)
{/*插入数据:在某个位置插入数据*/
int j=1;
LinkList q, p;
p = L;
while (p&&j < i)
{/*寻找需要插入的位置*/
p = p->next;
++j;
}
if (!p || j > i)
return ERROR;
q = (LinkList)malloc(sizeof(Node));
q->data = e;
q->next = p->next;
p->next = q;
return OK;
}
void InsertionHead(LinkList L,ElenType e)
{/*插入数据:头插法*/
LinkList p = L, q;
q = (LinkList)malloc(sizeof(Node));
q->data = e;
q->next = p->next;
p->next = q;
}
void InsertionTail(LinkList L, ElenType e)
{/*插入数据:尾插法*/
LinkList p=L, q;
while (p->next)
p = p->next;
q = (LinkList)malloc(sizeof(Node));
q->data = e;
q->next = NULL;
p->next = q;
}
void InsertionMenu(LinkList L)
{/*插入数据菜单*/
int i, j,e;
printf("请选择插入数据的方式:1、在某个位置插入数据\t2、头插法\t3:尾插法\n请选择:");
scanf_s("%d", &i);
switch (i)
{
case 1:
printf("请输入插入的位置:");
scanf_s("%d", &j);
printf("请输入插入的数据:");
scanf_s("%d", &e);
InsertionLocation(L, j, e);
break;
case 2:
printf("请输入插入的数据:");
scanf_s("%d", &e);
InsertionHead(L, e);
break;
case 3:
printf("请输入插入的数据:");
scanf_s("%d", &e);
InsertionTail(L, e);
break;
default:
printf("不存在该功能选项!\n");
break;
}
printf("插入数据后的链表中的数据为:");
Display(L);
}
int DeleteLocation(LinkList *L, int i)
{/*删除某个位置上的数据*/
LinkList q, p = *L;
int j = 1;
while (j++ < i && p)
p = p->next;
if (j > i + 1 || !p)
return ERROR;
q = p->next;
p->next = q->next;
free(q);
return OK;
}
int DeleteDataOne(LinkList L, ElenType e)
{/*删除某个数据*/
LinkList p=L , q;
while (p->next)
{/*结点不为空则运行*/
if (p->next->data == e)
{/*判断下一个结点是否符合要求*/
q = p->next;/*q继承下一个符合要求的结点*/
p->next = q->next;/*p指向下下个结点*/
free(q);/*释放q的空间*/
return OK;
}
p = p->next;/*若没有查找到符合要求结点,则结点后移*/
}
printf("不存在该数据!\n");
return ERROR;
}
int DeleteDataTwo(LinkList L, ElenType e)
{/*删除某个数据*/
LinkList p = L, q = L->next;
while (q)
{
if (q->data == e)
{
p->next = q->next;
free(q);
return OK;
}
p = q;
q = q->next;
}
printf("不存在该数据!\n");
return ERROR;
}
void DeleteMenu(LinkList L)
{/*删除结点菜单*/
int i,j;
printf("请选择删除结点的方式:1、删除某个位置上的数据\t2:删除某个数据—方式一\t3:删除某个数据—方式二\n请选择:");
scanf_s("%d", &i);
switch (i)
{
case 1:
printf("请输入删除的位置:");
scanf_s("%d", &j);
DeleteLocation(&L, j);
break;
case 2:
printf("请输入删除的数据:");
scanf_s("%d", &j);
DeleteDataOne(L, j);
break;
case 3:
printf("请输入删除的数据:");
scanf_s("%d", &j);
DeleteDataTwo(L, j);
break;
default:
printf("不存在该功能选项!\n");
break;
}
printf("删除数据后的链表中的数据为:");
Display(L);
}
int ClearList(LinkList *L)
{/*删除整个链表*/
LinkList p, q;
p = (*L)->next;
while (p)
{
q = p->next;
free(p);
p = q;
}
(*L)->next = NULL;
return OK;
}
int Length(LinkList L)
{/*计算链表的长度*/
LinkList p = L;
int length = 0;;
while (p->next)
{
length++;
p = p->next;
}
return length;
}
void menu()
{/*程序菜单*/
printf("程序的功能菜单:\n0:菜单\n1:创建链表\n2:插入数据\n3:删除结点\n4:单链表的整表删除\n5:计算链表的长度\n6:退出程序\n");
}
int main(void)
{
int i = 0;
LinkList L;
while (i != 6)
{
switch (i)
{
case 0:
menu();
break;
case 1:
Initialize(&L);
create(L);
printf("链表中的数据为:");
Display(L);
break;
case 2:
InsertionMenu(L);
break;
case 3:
DeleteMenu(L);
break;
case 4:
ClearList(&L);
Display(L);
break;
case 5:
printf("链表的长度为:%d\n", Length(L));
break;
default:
printf("不存在该功能选项!\n");
break;
}
printf("请输入需要执行的选项:");
scanf_s("%d", &i);
}
printf("感谢您的使用!\n");
return 0;
}
运行结果图: