3.2 双链表
3.2.1 定义
- 作用
方便找上一个结点。
typedef struct DNode {
ElemType data;
struct DNode* prior, * next;//指向上一个和下一个的结点
}DNode,*DLinklist;
//DNode强调是结点,*DLinklist强调是链表
//初始化双链表
bool InitDLinkList(DLinklist& L) {
L = (DNode*)malloc(sizeof(DNode));//分配一个头结点
if (L == NULL)return false;
L->prior = NULL;//头结点的prior永远指向null
L->next = NULL;
return true;
}
3.2.2 插入
-
步骤
1.插入节点的next指向后继节点;
2.后继节点的prior指向插入节点;
3.插入节点的prior指向前驱节点;
4.前驱节点的next指向插入节点。
//p后插s
bool InsertNextDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i )
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
//p前插s
//找到待插入位置的前驱节点,再进行后插
bool InsertPriorDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
3.2.3 删除
-
步骤
1.前驱节点的next指向后驱节点;
2.后继节点的prior指向前驱节点;
3.释放要删除的节点。
bool ListDelete(DLinklist& L, int i, ElemType& e)
{
if (i < 1)return false;
DNode* p;//指针p指向当前扫描到的结点
int j = 0;//当前p指向的是第几个结点
//循环找到第i-1个结点
p = L;//指向头结点
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
//i值不合法
if (p == NULL || p->next == NULL)return false;
DNode* q = p->next;//令q指向被删除结点
e = q->data;//用e返回元素的值
p->next = q->next;//将*q结点从链中断开
if (q->next != NULL)//q不是最后一个
{
q->next->prior = p;
}
free(q);//释放结点存储空间
return true;
}
3.2.4 销毁
相当于循环删除每个节点。
void DestoryList(DLinklist& L)
{
//循环释放各节点
DNode* p = L->next;
while (p != NULL)
{
DNode* q = p->next;
if (q != NULL)
{
p->next = q->next;
if (q->next != NULL)
{
q->next->prior = p;
}
free(q);
}
p = p->next;
}
free(L);//释放头结点
L = NULL;
}
3.2.5 查找
同单链表查找
时间复杂度:O(n)
* 双链表完整代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ElemType int
//----------------定义-----------------
typedef struct DNode {
ElemType data;
struct DNode* prior, * next;//指向上一个和下一个的结点
}DNode,*DLinklist;
//DNode强调是结点,*DLinklist强调是链表
//*DNode等价于DLinklist
//初始化双链表
bool InitDLinkList(DLinklist& L) {
L = (DNode*)malloc(sizeof(DNode));//分配一个头结点
if (L == NULL)return false;
L->prior = NULL;//头结点的prior永远指向null
L->next = NULL;
return true;
}
//---------------建立单链表---------------
//头插法建立单链表
DLinklist List_HeadInsert(DLinklist& L)
{
int m;
printf("\n1.手动输入\n2.自动生成\n");
scanf_s("%d", &m);
if (m == 1)
{
DNode* s;
int x;
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = x;
s->next = L->next;//新结点指针域指向原来的第一个结点
s->prior = L;
//头结点指向新结点
L->next = s;
scanf_s("%d", &x);
}
return L;
}
else if (m == 2)
{
DNode* s;
int n = 10;//结点个数
srand(time(0));//初始化随机数种子
while (n--)
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = rand() % 100 + 1;//随机产生100以内的数
s->next = L->next;
L->next = s;
}
}
else
{
printf("请重新输入!\n");
List_HeadInsert(L);
}
}
//尾插法建立链表
DLinklist List_TailInsert(DLinklist& L)
{
int m;
printf("\n1.手动输入\n2.自动生成\n");
scanf_s("%d", &m);
if (m == 1)
{
DNode* s, * r = L;//r为表尾指针
int x;
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = x;
s->prior = r;
//表尾指针指向新结点
r->next = s;
//更新表尾结点
r = s;
scanf_s("%d", &x);
}
r->next = NULL;//尾结点指针置空
return L;
}
else if (m == 2)
{
DNode* s, * r = L;
int n = 10;//结点个数
srand(time(0));//初始化随机数种子
while (n--)
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = rand() % 100 + 1;//随机产生100以内的数
r->next = s;
r = s;
}
r->next = NULL;
return L;
}
else
{
printf("请重新输入!\n");
List_TailInsert(L);
}
}
//-------------------插入操作-----------------------
//p后插s
bool InsertNextDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i )
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
//p前插s
//找到待插入位置的前驱节点,再进行后插
bool InsertPriorDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
//-----------------删除------------------
bool ListDelete(DLinklist& L, int i, ElemType& e)
{
if (i < 1)return false;
DNode* p;//指针p指向当前扫描到的结点
int j = 0;//当前p指向的是第几个结点
//循环找到第i-1个结点
p = L;//指向头结点
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
//i值不合法
if (p == NULL || p->next == NULL)return false;
DNode* q = p->next;//令q指向被删除结点
e = q->data;//用e返回元素的值
p->next = q->next;//将*q结点从链中断开
if (q->next != NULL)//q不是最后一个
{
q->next->prior = p;
}
free(q);//释放结点存储空间
return true;
}
//-----------------销毁------------------
void DestoryList(DLinklist& L)
{
//循环释放各节点
DNode* p = L->next;
while (p != NULL)
{
DNode* q = p->next;
if (q != NULL)
{
p->next = q->next;
if (q->next != NULL)
{
q->next->prior = p;
}
free(q);
}
p = p->next;
}
free(L);//释放头结点
L = NULL;
}
//---------------查找----------------
//按序号查找结点
DNode* GetElem(DLinklist L, int i)
{
if (i < 1)return NULL;
int j = 1;
DNode* p = L->next;//第1个结点指针赋给p
while (p != NULL && j < i)
{
p = p->next;
j++;
}
return p;
}
//按值查找
DNode* LocateElem(DLinklist L, ElemType e)
{
DNode* p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
if (p != NULL)
{
printf("Success!\n");
}
else
{
printf("没有这个值!\n");
}
return p;
}
void Menu()
{
printf("\n----------菜单----------\n");
printf("1.头插法创建\n2.尾插法创建\n");
printf("3.后插\n4.前插\n");
printf("5.删除节点\n6.销毁双链表\n");
printf("7.按序号查找\n8.按值查找\n");
}
void Listprint(DLinklist& L)
{
if (L == NULL)
{
printf("链表为空!\n");
return;
}
DLinklist t = L->next;
while (t->next != NULL)
{
printf("%d ", t->data);
t = t->next;
}
printf("%d\n", t->data);
}
int main()
{
DLinklist L;
InitDLinkList(L);
int x;
Menu();
while (~scanf_s("%d", &x)) {
if (x == 1)
{
List_HeadInsert(L);
Listprint(L);
}
else if (x == 2)
{
List_TailInsert(L);
Listprint(L);
}
else if (x == 3)
{
int pos;
ElemType data;
printf("请输入要插入的位置和值:\n");
scanf_s("%d %d", &pos,& data);
InsertNextDNode(L, pos,data);
Listprint(L);
}
else if (x == 4)
{
int pos;
ElemType data;
printf("请输入要插入的位置和值:\n");
scanf_s("%d %d", &pos, &data);
InsertPriorDNode(L, pos, data);
Listprint(L);
}
else if (x == 5)
{
int pos;
ElemType x;
printf("请输入要删除的位置:\n");
scanf_s("%d", &pos);
ListDelete(L, pos, x);
printf("已删除元素:%d\n", x);
Listprint(L);
}
else if (x == 6)
{
DestoryList(L);
printf("Success!\n");
Listprint(L);
}
else if (x == 7)
{
DNode* p;
int n;
printf("请输入需要查找的序号:\n");
scanf_s("%d", &n);
p = GetElem(L, n);
printf("查找结点的值:%d", p->data);
}
else if (x == 8)
{
DNode* p;
int n;
printf("请输入需要查找的结点值:\n");
scanf_s("%d", &n);
p = LocateElem(L, n);
}
Menu();
}
return 0;
}