单链表存储结构
带头结点的单链表,方便对链表的统一操作;不带头结点的链表首结点和非首结点的处理要区分。
单链表通过一个指向头结点或首结点的结点指针LinkList来管理链表。
typedef int ElemType;
typedef struct LNode {
ElemType data;
LNode* next;
}LNode,*LinkList;
基本操作
1.初始化
void InitList(LinkList& L) {
L = (LinkList)malloc(sizeof(LNode)); // 产生头结点,L指向此头结点
if (!L) exit(-1); // 存储分配失败
L->next = NULL; // 指针域为空,空链表
}
2.销毁
释放包括头结点在内的所有结点,只剩一个空指针LinkList。
void DestroyList(LinkList& L) {
LinkList p;
while (L) {
p=L->next;
free(L);
L = p;
}
}
3.清空
释放头结点外所有结点,保留头结点。
void ClearList(LinkList& L) {
LinkList p = L->next,q;
while (p) {
q = p->next;
free(p);
p = q;
}
L->next = NULL;
}
4.为空
头结点后为空。
bool ListEmpty(LinkList L) {
if (L->next)
return false;
else
return true;
}
5.长度
int ListLength(LinkList L) {
int i = 0;
LinkList p = L->next; //首结点
while (p) {
++i;
p = p->next;
}
return i;
}
6.获取元素
当第i个元素存在时,其值赋给e;
bool GetElem(LinkList L, int i, ElemType& e)
{
int j = 1; // j为计数器
LinkList p = L->next; // p指向首结点
while (p && j < i) // 向后查找,直到p指向第i个元素或p为空
{
p = p->next;
j++;
}
if (!p || j > i) // 第i个元素不存在
return false;
e = p->data; // 取第i个元素
return true;
}
7.定位元素
compare()是数据元素判定函数(满足为1,否则为0),返回L中第1个与e满足关系compare()的数据元素的位序;若这样的数据元素不存在,则返回值为0
int LocateElem(LinkList L, ElemType e, bool(*compare)(ElemType, ElemType))
{
int i = 0;
LinkList p = L->next; //首结点
while (p)
{
i++;
if (compare(p->data, e)) // 找到这样的数据元素
return i;
p = p->next;
}
return 0;
}
8.前驱
若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,返回true;否则操作失败,pre_e无定义,返回false
bool PriorElem(LinkList L, ElemType cur_e, ElemType& pre_e)
{
LinkList q, p = L->next; // p指向首结点
while (p->next) // p所指结点有后继
{
q = p->next; // q为p的后继
if (q->data == cur_e) //如果q的元素满足则返回前驱元素
{
pre_e = p->data;
return true;
}
p = q; // p向后移
}
return false;
}
9.后继
若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,返回true;否则操作失败,next_e无定义,返回false
bool NextElem(LinkList L, ElemType cur_e, ElemType& next_e)
{
LinkList p = L->next; // p指向首结点
while (p->next) // p所指结点有后继
{
if (p->data == cur_e) //p元素满足则返回后继元素
{
next_e = p->next->data;
return true;
}
p = p->next;
}
return false;
}
10.插入
第i个位置之前插入元素e;先寻找到第i-1个元素位置,然后在后面插入,i的范围为1<=i<=length+1。i为1时就是在头结点后插入,i=length+1时就是在尾部插入。
bool ListInsert(LinkList L, int i, ElemType e) { //不改变L,不用&
LinkList p = L;
int j = 0;
while (p && j < i-1) { // 寻找第i-1个结点
p = p->next;
++j;
}
if (!p || j > i-1) // i小于1或者大于表长
return false;
LinkList tmp = (LinkList)malloc(sizeof(LNode)); // 生成新结点
if (!tmp) exit(-1);
tmp->date = e; // 插入L中
tmp->next = p->next;
p->next = tmp;
return true;
}
11.删除
删除第i个元素,并由e返回其值。i的范围是1<=i<=length。
bool ListDelete(LinkList L, int i, ElemType& e) {
LinkList p = L;
int j = 0;
while (p->next && j < i-1) { // 寻找第i个结点,并令p指向其前驱
p = p->next;
++j;
}
if (!p->next || j > i - 1) // 删除位置不合理
return false;
LinkList q = p->next; // 删除并释放结点
e = q->data;
p->next = q->next;
free(q);
return true;
}
12.遍历
void ListTraverse(LinkList L, void(*vi)(ElemType)) {
LinkList p = L->next;
while (p) {
vi(p->data);
p = p->next;
}
printf("\n");
}
测试函数
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
void visit(ElemType e) {
printf("%d ", e);
}
bool compare(ElemType e1, ElemType e2) {
if (e1 == e2)
return true;
else
return false;
}
int main() {
ElemType e;
LinkList L;
InitList(L); //初始化
for (int j = 1; j <= 5; j++)
ListInsert(L, 1, j); //插入
printf("在L的表头依次插入1~5后:L=");
ListTraverse(L, visit);
printf("L是否空:i=%d(1:是 0:否)\n", ListEmpty(L));
ClearList(L);
printf("清空L后:L=");
ListTraverse(L, visit);
printf("L是否空:i=%d(1:是 0:否)\n", ListEmpty(L));
for (int j = 1; j <= 10; j++) //插入
ListInsert(L, j, j);
printf("在L的表尾依次插入1~10后:L=");
ListTraverse(L, visit);
if (GetElem(L, 5, e)) //获取元素
printf("第5个元素的值为%d\n", e);
else
printf("没有第5个元素\n");
if (GetElem(L, 13, e))
printf("第13个元素的值为%d\n", e);
else
printf("没有第13个元素\n");
if (e = LocateElem(L, 8, compare)) //定位元素
printf("元素8的位置为%d\n", e);
else
printf("没有值为8的元素\n");
if (e = LocateElem(L, 11, compare))
printf("元素11的位置为%d\n", e);
else
printf("没有值为11的元素\n");
if (PriorElem(L, 10, e)) //前驱
printf("元素10的前驱为%d\n", e);
else
printf("元素10无前驱\n");
if (NextElem(L, 10, e))
printf("元素10的后继为%d\n", e);
else
printf("元素10无后继\n");
if (PriorElem(L, 1, e)) //后继
printf("元素1的前驱为%d\n", e);
else
printf("元素1无前驱\n");
if (NextElem(L, 1, e))
printf("元素1的后继为%d\n", e);
else
printf("元素1无后继\n");
ListTraverse(L, visit);
printf("表长为%d\n", ListLength(L));
if (ListDelete(L, 3, e)) //删除
printf("删除第3个元素成功,其值为%d\n", e);
else
printf("删除第3个元素失败\n");
printf("依次输出L的元素:");
ListTraverse(L, visit);
DestroyList(L);
printf("销毁L后:L=%u\n", L);
return 0;
}
测试结果