目录
tips:本文章只介绍 线性表的链式存储结构!!!
其中,只介绍 单链表 与 双链表 !!!循环链表 和 静态链表 将发布在下个章节!!!
1.单链表
顺序表可随时存取表中的任意元素,但插入和删除操作需要移动大量元素。链式存储线性表时,不需要使用地址连续的存储单元,即不要求逻辑上相邻的元素在物理位置上也相邻,它通过“链”建立起数据元素之间的逻辑关系。因此插入和删除操作不需要移动元素,只需要修改指针,但也会失去顺序表可随机存取的特点!
1.1单链表的定义
线性表的链式存储又称单链表。它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。
单链表结点结构如下:
单链表中结点类型的描述如下:
typedef struct LNode
{
ElemType data;
struct LNode* next;
}LNode,*LinkList;
通常用头指针来标识一个单链表,此外,为了操作上的方便,在单链表的第一个结点之前附加一个结点,称为头结点。头结点的数据域可以不设任何信息,也可以记录表长等信息。头结点的指针域指向线性表中的第一个元素结点。
如图:
引入头结点后,可以带来两个优点:
1.由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置的操作一致。
2.无论链表是否为空,其头指针都是指向头结点的非空指针,因此空表和非空表的处理也就得到了统一。
1.2 单链表的基本操作
//初始化表
//判空操作
//求表长操作
//插入元素操作
//遍历元素操作
//清空表操作
//整表创建操作
//按位查找元素操作
//按值查找元素操作
//删除元素操作
1.2.1 预备代码
//线性表的链式存储的实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20
typedef int Status;
typedef int ElemType;
typedef struct Node
{
ElemType data;
struct Node* next;
}Node;
typedef struct Node* LinkList; //定义LinkList
1.2.2 初始化链表
//初始化链式线性表
Status InitList(LinkList* L)
{
//开辟内存空间
*L = (LinkList)malloc(sizeof(Node)); //创建头结点,并让头指针L指向此结点
if (!(*L))
{
return ERROR;
}
//头结点指针域置空
(*L)->next = NULL;
}
1.2.3 判空
/* 初始条件:链式线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{
if (L->next)
{
return FALSE;
}
else
{
return TRUE;
}
}
1.2.4 求表长
/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
LinkList p = L->next;
int i = 0;
while (p)
{
p = p->next;
i++;
}
return i;
}
上面代码中 p = p->next 的步骤是:p指针访问 “p指针指向的结构体(结点)” 里的成员next,获取next(指针域)里存放的地址,并把该地址赋值给p指针,即让p指针指向下一个结点。
1.2.5 整表创建操作(头插法)
/* 随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateList_Head(LinkList* L, int n)
{
srand(time(0)); //初始化随机种子
//创建一个带头结点的单链表
(*L) = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
//在头结点后,循环插入n个随机数
LinkList p;
for (int i = 0; i < n; i++)
{
//创建新的结点,并让p指向新的结点
p = (LinkList)malloc(sizeof(Node));
p->data = rand() % 100 + 1; //随机生成100以内的数字
p->next = (*L)->next; //把头结点后面的结点(第一个结点)的地址 赋值 给新指针p指向结点的指针域
(*L)->next = p;
}
}
1.2.6 遍历元素操作
/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status visit(ElemType c)
{
printf("%d ", c);
return OK;
}
void ListTraverse(LinkList L)
{
LinkList p = L->next; //指针p指向头结点
while (p)
{
visit(p->data);
p = p->next; //指针p指向下一个结点
}
printf("\n");
return OK;
}
测试代码(对以上的代码进行测试):
1.2.7 清空表操作
/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ListClear(LinkList* L)
{
LinkList p, q;
//指针p指向第一个结点
p = (*L)->next;
while (p)
{
q = p->next; //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
free(p); //释放 p指向的结点
p = q; //让指针p指向(新的)第一个结点
}
(*L)->next = NULL; //头结点的指针域置为空
return OK;
}
上面代码中,p = (*L)->next 的步骤是:头指针(L)访问其指向的结构体(头结点)里的成员(next),获取next里存放的地址,并把该地址赋值给p。即让p指向 头指针指向结点 的后一个结点。
测试代码
1.2.8 整表创建操作(尾插法)
/* 随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateList_Tail(LinkList* L, int n)
{
LinkList p, r; //声明两个结构体指针
srand(time(0)); //初始化随机种子
(*L) = (LinkList)malloc(sizeof(Node)); //创建头结点
r = (*L); //指针r 指向链表尾部的结点
for (int i = 0; i < n; i++)
{
p = (Node*)malloc(sizeof(Node)); //创建新结点,让p指向新结点
p->data = rand() % 100 + 1;
r->next = p; //把新结点的地址 赋值给 表尾结点的指针域
r = p; //让r指向新的表尾结点
}
r->next = NULL;
}
测试代码
1.2.9 插入元素操作
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList* L, int i, ElemType e)
{
LinkList p, s;
p = (*L); //p指向头结点
int j = 1;
while (p && j < i) //逻辑与,同真才为真,即需要同时满足两个条件才进入循环
{
p = p->next;
j++;
}
if (!p || j > i) //满足p为空 或 j>i 其中一个条件就进入循环
{
return ERROR;
}
s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next; //把p的后继结点的地址 赋值给 s的指针域
p->next = s; //再把s的地址 赋值给 p的指针域
return OK;
}
测试代码:
1.2.10 按位查找元素操作
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
//按位查找
Status GetElem(LinkList L, int i, ElemType* e)
{
LinkList p;
p = L->next; //指针p指向第一个结点
int j = 1; //当查找的元素i为1时,直接返回p指向结点的数据域
while (p && j < i) //逻辑与,同真才为真,同时满足两个条件才进入循环
{
p = p->next; //让p指向下一个结点
j++;
}
if (!p || j > i) //逻辑与,同假为假,即满足其中一个条件,便可进入循环
{
return ERROR;
}
*e = p->data;
return OK;
}
1.2.11 按值查找元素操作
/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
Status LocateElem(LinkList L, ElemType e)
{
LinkList p = L->next; //p指向头结点的后继结点(第一个结点)
int i = 1;
while (p)
{
if (p->data == e)
{
return i;
}
else
{
p = p->next;
i++;
}
}
return 0;
}
1.2.12 删除元素操作
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList* L, int i, ElemType* e)
{
LinkList p, q;
p = (*L); // p指向头结点
int j = 1;
while (p->next && j < i)
{
p = p->next;
j++;
}
if (!(p->next) || j > i)
{
return ERROR;
}
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return OK;
}
1.3 单链表实现完整代码:
#define _CRT_SECURE_NO_WARNINGS 1
//线性表的链式存储的实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20
typedef int Status;
typedef int ElemType;
typedef struct Node
{
ElemType data;
struct Node* next;
}Node;
typedef struct Node* LinkList; //定义LinkList
//初始化链式线性表
Status InitList(LinkList* L)
{
//开辟内存空间
*L = (LinkList)malloc(sizeof(Node)); //创建头结点,并让头指针L指向此结点
if (!(*L))
{
return ERROR;
}
//头结点指针域置空
(*L)->next = NULL;
}
/* 初始条件:链式线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{
if (L->next)
{
return FALSE;
}
else
{
return TRUE;
}
}
/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
LinkList p = L->next;
int i = 0;
while (p)
{
p = p->next;
i++;
}
return i;
}
/* 随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateList_Head(LinkList* L, int n)
{
srand(time(0)); //初始化随机种子
//创建一个带头结点的单链表
(*L) = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
//在头结点后,循环插入n个随机数
LinkList p;
for (int i = 0; i < n; i++)
{
//创建新的结点,并让p指向新的结点
p = (LinkList)malloc(sizeof(Node));
p->data = rand() % 100 + 1; //随机生成100以内的数字
p->next = (*L)->next; //把头结点后面的结点(第一个结点)的地址 赋值 给新指针p指向结点的指针域
(*L)->next = p;
}
}
/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status visit(ElemType c)
{
printf("%d ", c);
return OK;
}
void ListTraverse(LinkList L)
{
LinkList p = L->next;
while (p)
{
visit(p->data);
p = p->next;
}
printf("\n");
return OK;
}
/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ListClear(LinkList* L)
{
LinkList p, q;
//指针p指向第一个结点
p = (*L)->next;
while (p)
{
q = p->next; //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
free(p); //释放 p指向的结点
p = q; //让指针p指向(新的)第一个结点
}
(*L)->next = NULL; //头结点的指针域置为空
return OK;
}
/* 随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateList_Tail(LinkList* L, int n)
{
LinkList p, r;
srand(time(0)); //初始化随机种子
(*L) = (LinkList)malloc(sizeof(Node)); //创建头结点
r = (*L); //指针r 指向链表尾部的结点
for (int i = 0; i < n; i++)
{
p = (Node*)malloc(sizeof(Node)); //创建新结点,让p指向新结点
p->data = rand() % 100 + 1;
r->next = p; //把新结点的地址 赋值给 表尾结点的指针域
r = p; //让r指向新的表尾结点
}
r->next = NULL;
}
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList* L, int i, ElemType e)
{
LinkList p, s;
p = (*L); //p指向头结点
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i) //满足p为空 或 j>i 其中一个条件就进入循环
{
return ERROR;
}
s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next; //把p的后继结点的地址 赋值给 s的指针域
p->next = s; //再把s的地址 赋值给 p的指针域
return OK;
}
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
//按位查找
Status GetElem(LinkList L, int i, ElemType* e)
{
LinkList p;
p = L->next;
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)
{
return ERROR;
}
*e = p->data;
return OK;
}
/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
Status LocateElem(LinkList L, ElemType e)
{
LinkList p = L->next; //p指向头结点的后继结点(第一个结点)
int i = 1;
while (p)
{
if (p->data == e)
{
return i;
}
else
{
p = p->next;
i++;
}
}
return 0;
}
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList* L, int i, ElemType* e)
{
LinkList p, q;
p = (*L); // p指向头结点
int j = 1;
while (p->next && j < i)
{
p = p->next;
j++;
}
if (!(p->next) || j > i)
{
return ERROR;
}
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return OK;
}
void test01()
{
//1.线性单链表的整表创建(头插法)测试:
LinkList La;
CreateList_Head(&La, 10); //参数以地址传入,指针接收
//表长
int i_length = 0;
i_length = ListLength(La);
printf("La的表长为:%d\n", i_length); //La的表长为:10
//判空
Status i_empty;
i_empty = ListEmpty(La);
printf("表La是否为空(1为是/0为否):%d\n", i_empty); //表La是否为空(1为是/0为否):0
//遍历
ListTraverse(La); //37 81 45 81 59 36 78 59 86 79
printf("----------------------------------------------\n");
//2.清空表
ListClear(&La);
//表长
i_length = ListLength(La);
printf("La的表长为:%d\n", i_length); //La的表长为:0
//判空
i_empty = ListEmpty(La);
printf("表La是否为空(1为是/0为否):%d\n", i_empty); //表La是否为空(1为是/0为否):1
printf("----------------------------------------------\n");
//3.线性单链表的整表创建(尾插法)测试:
CreateList_Tail(&La, 5);
//表长
i_length = ListLength(La);
printf("La的表长为:%d\n", i_length); //La的表长为:5
//判空
i_empty = ListEmpty(La);
printf("表La是否为空(1为是/0为否):%d\n", i_empty); //表La是否为空(1为是/0为否):0
//遍历
ListTraverse(La); //65 26 59 17 11
}
void test02()
{
LinkList Lb;
//初始化
InitList(&Lb);
//在Lb表头循环插入10个元素
for (int i = 0; i < 10; i++)
{
ListInsert(&Lb, 1, i);
}
ListTraverse(Lb); //9 8 7 6 5 4 3 2 1 0
//按位查找
//int i = 5;
//ElemType e = 0;
//GetElem(Lb, i, &e);
//printf("表Lb的第 %d 个元素是 %d \n", i, e); //表Lb的第 5 个元素是 5
//按值查找
//ElemType e = 11;
//int i = LocateElem(Lb, e);
//printf("表中值为 %d 的元素在第%d个位置(0表示不存在该元素)\n", e, i);
//按位删除
int i = 1;
ElemType e;
ListDelete(&Lb, i, &e);
printf("Lb表中被删除的第 %d 个元素为 %d \n", i, e); //Lb表中被删除的第 1 个元素为 9
ListTraverse(Lb); //8 7 6 5 4 3 2 1 0
int j = ListLength(Lb);
printf("表长为:%d\n", j); //表长为:9
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
2.双链表( Double Linked List)
单链表结点中只有一个指向其后继的指针,使得单链表只能从头结点依次顺序地向后遍历。要访问某个结点的前驱结点,只能从头开始遍历,访问后继结点的时间复杂度为O(1),访问前驱结点的时间复杂度为O(n).
为了解决上述单链表的缺点,引入了 双链表,双链表结点中有两个指针prior 和 next,分别指向其前驱结点和后继结点。
如图
双链表中结点类型的描述如下:
typedef struct DNode
{
ElemType data;
struct DNode* prior;
struct DNode* next;
}DNode,* DLinkList;
2.1 基本操作
tips:双链表中的按值查找和按位查找的操作与单链表的相同。但双链表在插入和删除操作的实现上,与单链表有着较大的不同!
//双向链表
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef int ElemType;
typedef struct DNode
{
ElemType data;
struct DNode* prior;
struct DNode* next;
}DNode,* DLinkList;
//typedef struct DNode* DLinkList;
2.1.1 整表创建(尾插法)
/* 随机产生n个元素的值,建立带表头结点的双链表DL(尾插法) */
void CreateList_Tail(DLinkList* DL, int n)
{
//srand(time(0)); //初始化随机种子
//创建一个带头结点的单链表
(*DL) = (DLinkList)malloc(sizeof(DNode));
(*DL)->prior = NULL;
(*DL)->next = NULL;
//在头结点后,循环插入n个随机数
DLinkList s;
DLinkList p;
p = (*DL); //指针p指向头结点
for (int i = 0; i < n; i++)
{
//创建新的结点
s = (DLinkList)malloc(sizeof(DNode));
//s->data = rand() % 100 + 1; //随机生成100以内的数字
s->data = i;
//
s->prior = p;
s->next = p->next;
p->next = s;
p = s; //指针向后移动
}
}
2.1.2 求表长
//求表长
/* 初始条件:双链表DL已存在。操作结果:返回DL中数据元素个数 */
int ListLength(DLinkList DL)
{
DLinkList p = DL->next;
int i = 0;
while (p) //若p不为空
{
p = p->next;
i++;
}
//若为空表
return i;
}
2.1.3 判空
//判空
/* 初始条件:双链表 DL已存在。操作结果:若 DL为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(DLinkList DL)
{
if (DL->next)
{
return FALSE;
}
else
{
return TRUE;
}
}
2.1.4 遍历
/* 初始条件:双链表DL已存在 */
/* 操作结果:依次对DL的每个数据元素输出 */
Status visit(ElemType c)
{
printf("%d ", c);
return OK;
}
void ListTraverse(DLinkList DL)
{
DLinkList p = DL->next;
while (p)
{
visit(p->data);
p = p->next;
}
printf("\n");
}
测试代码:
2.1.5 清空
/* 初始条件:双链表DL已存在。操作结果:将DL重置为空表 */
Status ListClear(DLinkList* L)
{
DLinkList p, q;
//指针p指向第一个结点
p = (*L)->next;
while (p)
{
q = p->next; //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
free(p); //释放 p指向的结点
p = q; //让指针p指向(新的)第一个结点
}
(*L)->next = NULL; //头结点的指针域置为空
return OK;
}
测试代码:
2.1.6 初始化表
//初始化双链表
Status ListInit(DLinkList* DL)
{
(*DL) = (DLinkList)malloc(sizeof(DNode));
if (!(*DL))
{
return ERROR;
}
//头结点的前后指针域置空
(*DL)->prior = NULL;
(*DL)->next = NULL;
return OK;
}
测试代码:
2.1.7 按位插入元素
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(DLinkList* DL, int i, ElemType e)
{
DLinkList p, s;
p = (*DL); //p指向头结点
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i) //满足p为空 或 j>i 其中一个条件就进入循环
{
return ERROR;
}
s = (DLinkList)malloc(sizeof(DNode));
s->data = e;
s->prior = p;
s->next = p->next;
p->next = s;
p = s; //指针向后移动
return OK;
}
测试代码:
2.1.8 按位查找
//按位查找
Status GetElem(DLinkList DL, int i, ElemType* e)
{
DLinkList p;
p = DL->next;
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)
{
return ERROR;
}
*e = p->data;
return OK;
}
测试代码:
2.1.9 按值查找
//按值查找
Status LocateElem(DLinkList L, ElemType e)
{
DLinkList p = L->next; //p指向头结点的后继结点(第一个结点)
int i = 1;
while (p)
{
if (p->data == e)
{
return i;
}
else
{
p = p->next;
i++;
}
}
return 0;
}
测试代码:
2.1.10 按位删除
//删除
Status ListDelete(DLinkList* L, int i, ElemType* e)
{
DLinkList p,q;
p = (*L); // p指向头结点
int j = 1;
while (p->next && j < i)
{
p = p->next;
j++;
}
if (!(p->next) || j > i)
{
return ERROR;
}
q = p->next;
p->next = q->next;
p->next->prior = q->prior;
*e = q->data;
free(q);
return OK;
}
测试代码:
2.2 双链表实现完整代码
#define _CRT_SECURE_NO_WARNINGS 1
//双向链表
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef int ElemType;
typedef struct DNode
{
ElemType data;
struct DNode* prior;
struct DNode* next;
}DNode,* DLinkList;
//typedef struct DNode* DLinkList;
//初始化双链表
Status ListInit(DLinkList* DL)
{
(*DL) = (DLinkList)malloc(sizeof(DNode));
if (!(*DL))
{
return ERROR;
}
//头结点的前后指针域置空
(*DL)->prior = NULL;
(*DL)->next = NULL;
return OK;
}
//判空
/* 初始条件:双链表 DL已存在。操作结果:若 DL为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(DLinkList DL)
{
if (DL->next)
{
return FALSE;
}
else
{
return TRUE;
}
}
//求表长
/* 初始条件:双链表DL已存在。操作结果:返回DL中数据元素个数 */
int ListLength(DLinkList DL)
{
DLinkList p = DL->next;
int i = 0;
while (p) //若p不为空
{
p = p->next;
i++;
}
//若为空表
return i;
}
/* 随机产生n个元素的值,建立带表头结点的双链表DL(尾插法) */
void CreateList_Tail(DLinkList* DL, int n)
{
//srand(time(0)); //初始化随机种子
//创建一个带头结点的单链表
(*DL) = (DLinkList)malloc(sizeof(DNode));
(*DL)->prior = NULL;
(*DL)->next = NULL;
//在头结点后,循环插入n个随机数
DLinkList s;
DLinkList p;
p = (*DL); //指针p指向头结点
for (int i = 0; i < n; i++)
{
//创建新的结点
s = (DLinkList)malloc(sizeof(DNode));
//s->data = rand() % 100 + 1; //随机生成100以内的数字
s->data = i;
//
s->prior = p;
s->next = p->next;
p->next = s;
p = s; //指针向后移动
}
}
/* 初始条件:双链表DL已存在 */
/* 操作结果:依次对DL的每个数据元素输出 */
Status visit(ElemType c)
{
printf("%d ", c);
return OK;
}
void ListTraverse(DLinkList DL)
{
DLinkList p = DL->next;
while (p)
{
visit(p->data);
p = p->next;
}
printf("\n");
}
/* 初始条件:双链表DL已存在。操作结果:将DL重置为空表 */
Status ListClear(DLinkList* L)
{
DLinkList p, q;
//指针p指向第一个结点
p = (*L)->next;
while (p)
{
q = p->next; //指针q指向 p指向结点的 后一个结点(把p指向结点 后一个结点的地址赋值给q)
free(p); //释放 p指向的结点
p = q; //让指针p指向(新的)第一个结点
}
(*L)->next = NULL; //头结点的指针域置为空
return OK;
}
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(DLinkList* DL, int i, ElemType e)
{
DLinkList p, s;
p = (*DL); //p指向头结点
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i) //满足p为空 或 j>i 其中一个条件就进入循环
{
return ERROR;
}
s = (DLinkList)malloc(sizeof(DNode));
s->data = e;
s->prior = p;
s->next = p->next;
p->next = s;
p = s; //指针向后移动
return OK;
}
//按位查找
Status GetElem(DLinkList DL, int i, ElemType* e)
{
DLinkList p;
p = DL->next;
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)
{
return ERROR;
}
*e = p->data;
return OK;
}
//按值查找
Status LocateElem(DLinkList L, ElemType e)
{
DLinkList p = L->next; //p指向头结点的后继结点(第一个结点)
int i = 1;
while (p)
{
if (p->data == e)
{
return i;
}
else
{
p = p->next;
i++;
}
}
return 0;
}
//删除
Status ListDelete(DLinkList* L, int i, ElemType* e)
{
DLinkList p,q;
p = (*L); // p指向头结点
int j = 1;
while (p->next && j < i)
{
p = p->next;
j++;
}
if (!(p->next) || j > i)
{
return ERROR;
}
q = p->next;
p->next = q->next;
p->next->prior = q->prior;
*e = q->data;
free(q);
return OK;
}
void test01()
{
//初始化表
DLinkList DL;
Status i_init = ListInit(&DL);
printf("%d\n", i_init); //1
//求表长
int i_length = ListLength(DL);
printf("DL的长度为:%d\n", i_length); //DL的长度为:0
//判空
Status i_empty = ListEmpty(DL);
printf("DL是否为空(1为是/0为否):%d\n", i_empty); // DL是否为空(1为是 / 0为否):1
printf("--------------------------------------------\n");
//在表头循环插入0~9
for (int i = 0; i < 10; i++)
{
ListInsert(&DL, 1, i);
}
//求表长
i_length = ListLength(DL);
printf("DL的长度为:%d\n", i_length); //DL的长度为:10
//判空
i_empty = ListEmpty(DL);
printf("DL是否为空(1为是/0为否):%d\n", i_empty); //DL是否为空(1为是 / 0为否):0
//遍历
ListTraverse(DL); //9 8 7 6 5 4 3 2 1 0
按位查找
//int i = 1;
//ElemType e = 0;
//GetElem(DL, i, &e);
//printf("DL表中第 %d 个元素是 %d \n", i, e); //DL表中第 1 个元素是 9
//按值查找
//ElemType e = 9;
//int i = LocateElem(DL, e);
//printf("表中值为 %d 的元素在第%d个位置(0表示不存在该元素)\n", e, i); //表中值为 9 的元素在第1个位置(0表示不存在该元素)
printf("--------------------------------------------\n");
//按位删除
int i = 1;
ElemType e;
ListDelete(&DL, i, &e);
printf("DL表中被删除的第 %d 个元素为 %d \n", i, e); //DL表中被删除的第 1 个元素为 9
ListTraverse(DL); //8 7 6 5 4 3 2 1 0
int j = ListLength(DL);
printf("表长为:%d\n", j); //表长为:9
}
void test02()
{
DLinkList DL;
CreateList_Tail(&DL, 10);
//求表长
int i_length = ListLength(DL);
printf("DL的长度为:%d\n", i_length); //DL的长度为:10
//判空
Status i_empty = ListEmpty(DL);
printf("DL是否为空(1为是/0为否):%d\n", i_empty); //DL是否为空(1为是 / 0为否):0
//遍历
ListTraverse(DL); //0 1 2 3 4 5 6 7 8 9
printf("----------------------------------\n");
//清空
ListClear(&DL);
//求表长
i_length = ListLength(DL);
printf("DL的长度为:%d\n", i_length);
//判空
i_empty = ListEmpty(DL);
printf("DL是否为空(1为是/0为否):%d\n", i_empty);
ListTraverse(DL); //(空)
printf("----------------------------------\n");
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}