线性表的链式存储结构称为链表。线性表采用链式存储时,最简单,最常用的方法是在每个结点中设置一个指针域用于指向其后继结点,这样构成的链表称为单链表;另一种采用的方法是在每个结点中设置两个指针域,分别用于指向其前驱结点和后继结点,这样构成的链表称为双链表。
在链表中通常每个链表都带有一个头结点,并通过头结点的指针唯一表识该链表,称为头指针,指向尾结点的指针称为尾指针。
在单链表中,由于每个结点只包含一个指向后继结点的指针,所有当访问一个结点后只能访问它的后继结点,而无法访问他的前驱结点。
单链表的实现:
1.声明单链表类型
typedef int ElemType; //元素类型
typedef struct LNode
{
ElemType data; //存放元素值
struct LNode * next; //指向后继结点
} LinkNode; //单链表结点类型
2.初始化链表
void InitList(LinkNode * &L)
{
L = (LinkNode*)malloc(sizeof(LinkNode));
L->next = NULL; //创建头节点,其next域置为NULL
}
3.销毁链表
void DestoryList(LinkNode * &L)
{
LinkNode *pre = L, *p = L->next;//pre指向结点p的前驱结点
while (p != NULL) //扫描单链表L
{
free(pre); //释放pre结点
pre = p;
p = p->next; //pre, p同步后移一个结点
}
free(pre); //循环结束时p为NULL,pre指向尾结点,释放它
}
4.头插法建立单链表
void CreateListF(LinkNode * &L, ElemType a[], int n)
{
LinkNode * s;
L = (LinkNode*)malloc(sizeof(LinkNode));
L->next = NULL; //创建头节点,其next域置为NULL
for (int i = 0; i < n; i++) //循环建立数据结点s
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = a[i]; //创建数据结点s
s->next = L->next; //将结点s插入到首结点之间,头节点之后
L->next = s;
}
}
5.尾插法创建单链表
void CreateListR(LinkNode * &L, ElemType a[], int n)
{
LinkNode * s,*r;
L = (LinkNode*)malloc(sizeof(LinkNode));//创建头节点
r = L; //r始终指向尾结点,初始化时指向头节点
for (int i = 0; i < n; i++)
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = a[i]; //创建数据结点s
r->next = s; //将结点s插入结点r之后
r= s;
}
r->next = NULL; //尾结点的next域置为NULL
}
6.打印单链表
void DispList(LinkNode *L)
{
LinkNode *p = L->next; //指向首结点
while (p != NULL); //p不为NULL时,输出p的结点的data域
{
printf("%d ", p->data);
p = p->next; //p指向下一个结点
}
printf("\n");
}
7.判断单链表是否为空表
bool ListEmpty(LinkNode * L)
{
return (L -> next == NULL);
}
8.求单链表的长度
int ListLength(LinkNode * L)
{
int n = 0;
LinkNode * p = L;
while (p->next != NULL)
{
n++;
p = p->next;
}
return n;
}
9.求单链表中某元素值
bool GetElem(LinkNode *L, int i, ElemType &e)
{
int j = 0;
LinkNode *p = L; //p指向头节点,j置为0(头节点序号为0)
if (i <= 0)return false; //i错误返回false
while (j < i&&p != NULL) //找到第i个结点p
{
j++;
p = p->next;
}
if (p == NULL) return false; //不存在第i个数据节点,返回false
else //存在第i个数据节点,返回true
{
e = p->data;
return true;
}
}
10.按元素查找
int LocateElem(LinkNode *L, ElemType e) {
int i = 1;
LinkNode *p = L->next; //p指向头节点,i置为1(首节点序号为1)
while (p != NULL && p->data != e) //查找data值为e的结点,其序号为i
{
p = p->next;
i++;
}
if (p == NULL)
return 0; //不存在值为e的结点,返回0
else
return i; //存在值为e的结点,返回i
}
11.插入数据元素
bool ListInsert(LinkNode * &L, int i, ElemType e)
{
int j = 0;
LinkNode *p = L, *s; //p指向头节点,j置为0(头节点序号为0)
if (i <= 0) return false; //i错误返回false
while (j < i - 1 && p != NULL) //查找第i-1个结点p
{
j++;
p = p->next;
}
if (p == NULL) return false; //未找到第i-1个结点,返回false
else //找到第i-1个结点,插入新结点并返回false
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = e; //创建新结点s,其data域置为e
s->next = p->next; //将结点s插入到结点p之后
p->next = s;
return true;
}
}
12.删除数据元素
bool ListDelete(LinkNode * &L, int i, ElemType &e)
{
int j = 0;
LinkNode *p = L, *q; //p指向头节点,j置为0(头节点序号为0)
if (i <= 0) return false; //i错误返回false
while (j < i - 1 && p != NULL) //查找第i-1个结点p
{
j++;
p = p->next;
}
if (p == NULL) return false; //未找到第i-1个结点,返回false
else //找到第i-1个结点
{
q = p->next; //q指向第i个结点
if (q == NULL)return false; //若不存在第i个结点,返回false
e = q->data;
p->next = q->next; //从单链表中删除q结点
free(q); //释放q结点
return true; //返回true表示成功删除第i个结点
}
}
13.主函数
int main()
{
LinkNode *LN;
ElemType data[] = { 1,23,4,5,6,5,7657 },a;
InitList(LN);
CreateListF(LN, data,7);
printf("按头插法插入链表为:");
DispList(LN);
CreateListR(LN, data, 7);
printf("按尾插法插入链表为:");
DispList(LN);
printf("链表是否为空:%s\n",ListEmpty(LN) ? "true" : "false");
printf("链表长度为:%d\n",ListLength(LN));
GetElem(LN, 2, a);
printf("第 2 个元素为:%d\n", a);
printf("元素值为 23 的元素在第 %d 个\n", LocateElem(LN, 23));
ListInsert(LN,3,88);
printf("在第 3 个插入元素 88 后链表为:");
DispList(LN);
ListDelete(LN,4,a);
printf("删除第 4 个元素后链表为:");
DispList(LN);
DestoryList(LN);
getchar();
return 0;
}
运行结果为:
按头插法插入链表为:7657 5 6 5 4 23 1
按尾插法插入链表为:1 23 4 5 6 5 7657
链表是否为空:false
链表长度为:7
第 2 个元素为:23
元素值为 23 的元素在第 2 个
在第 3 个插入元素 88 后链表为:1 23 88 4 5 6 5 7657
删除第 4 个元素后链表为:1 23 88 5 6 5 7657