前言
单链表的局限性:无法逆向检索,有时候会不太方便,我们在单链表每个结点里增加一个指向其直接前驱的指针域prior,这样就形成了两条方向不同的链,故称为双向链表
双向链表的储存结构
#include <stdio.h>
#define TRUE 1
#define FALSE 0
typedef int DataType;
//双向链表结点类型
typedef struct DNode
{
DataType data;
struct DNode* prior, * next;//前驱和后继指针
}DNode,*DLinkList;
初始化双向链表(带头节点)
//初始化双向链表(带头节点)
bool InitDLinkList(DLinkList& L)
{
L = new DNode;
if (L == NULL)//内存不足,分配失败
{
printf("内存不足,分配失败!\n");
return FALSE;
}
L->prior = NULL;//头结点的prior始终指向NULL
L->next = NULL;//没有后继结点
return TRUE;
}
判断双链表是否为空(带头结点)
//判断双链表是否为空(带头结点)
bool Empty(DLinkList L)
{
if (L->next == NULL)
return TRUE;
else
return FALSE;
}
双向链表尾插法建表
//双向链表尾插法建表
void DList_TailInsert(DLinkList& L)
{
L = new DNode;
L->next = NULL;
L->prior = NULL;
DNode* s, *r;
r = L;
int x;
scanf("%d", &x);
while (1)
{
if (x != 9999)
{
s = new DNode;
s->data = x;
r->next = s;
s->prior = r;
r = s;
scanf("%d", &x);
}
if (x == 9999)
break;
}
r->next = NULL;
}
双向链表头插法建表
//双向链表头插法建表
void DList_HeadInsert(DLinkList& L)
{
L = new DNode;
L->next = NULL;
L->prior = NULL;
DNode* s;
int x;
scanf("%d", &x);
while (1)
{
if (x != 9999)
{
s = new DNode;
s->data = x;
if (L->next == NULL)//当插入第一个结点的时候
{
s->next = L->next;
s->prior = L;
L->next = s;
}
if (L->next != NULL)
{
s->next = L->next;
L->next->prior = s;
s->prior = L;
L->next = s;
}
scanf("%d", &x);
}
if (x == 9999)
break;
}
}
双向链表的后插操作
bool InsertNextDNode(DNode* p, DNode* s)
{
s->next = p->next;
p->next->prior = s;
p->next = s;
s->prior = p;
}
此代码有一个问题,就是当p为最后一个结点的时候,p->next为NULL,程序中的第二行会出现空指针的错误,所以,为了避免这个问题,我么需要对插入的p结点的位置进行一个判断
优化代码如下:
bool InsertNextDNode(DNode* p, DataType e)
{
DNode* s;
if (p == NULL )
{
printf("插入位置不合法!\n");
return FALSE;
}
s = new DNode;
s->data = e;
s->next = p->next;
if (p->next != NULL)
p->next->prior = s;
p->next = s;
s->prior = p;
return TRUE;
}
这里我们可以发现,当我们双向链表完成后插操作后,我们按位序插入和前插操作就不用向之前那样麻烦了,只要找到需要插入的位置,直接就能通过prior指针访问到他的前驱结点,在对前驱结点完成后插操作就可以了
双向链表前插操作
//双向链表前插操作
bool InsertpriorDNode(DNode* p, DataType e)
{
DNode* s;
if (p == NULL)
{
printf("插入位置不合法!\n");
return FALSE;
}
s = new DNode;
if (s == NULL)
{
printf("内存申请失败!\n");
return FALSE;
}
s->data = e;
s->next = p->prior->next;
p->prior = s;
p->prior->next = s;
s->prior = p->prior;
return TRUE;
}
双链表按位序插入
//双链表按位序插入
bool InsertDLink(DLinkList& L, int i, DataType e)
{
if (i < 1)
{
printf("插入位置不合法!\n");
return FALSE;
}
DNode* s,*p;
s = new DNode;
s->data = e;
p = L->next;
int j = 1;
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{
printf("插入位置不合法!\n");
return FALSE;
}
s->next = p->next;
p->next->prior = s;
p->next = s;
s->prior = p;
return TRUE;
}
双链表带头结点的删除结点
//双链表带头结点的删除结点
bool DeleteDNode(DLinkList& L,int i,DataType &e)
{
if (i < 1)
{
printf("删除的位置不合法!\n");
return FALSE;
}
DNode * p;
int j = 0;
p = L;
while (p != NULL && j < i-1)//循环找到要删除的p结点
{
p = p->next;
j++;
}
if (p == NULL)
{
printf("删除的位置不合法!\n");
return FALSE;
}
if (p->next == NULL)//如果p为最后一个结点
{
p->prior->next = p->next;
}
if (p->next != NULL)//如果p不为最后一个结点
{
p->prior->next = p->next;
p->next->prior = p->prior;
}
e = p->data;
delete p;
return TRUE;
}
删除指定结点
//删除指定结点
bool DeleteDNode(DNode* p)
{
if(p==NULL)
{
printf("删除的位置不合法!\n");
return FALSE;
}
if (p->next == NULL)//如果p为最后一个结点
{
p->prior->next = p->next;
}
if (p->next != NULL)//如果p不为最后一个结点
{
p->prior->next = p->next;
p->next->prior = p->prior;
}
delete p;
return TRUE;
}
带头结点的双链表按位查找,返回第i个元素
//带头结点的双链表按位查找,返回第i个元素
DNode* GetElem(DLinkList L, int i)
{
if (i < 1)
{
printf("查找的位序不合法!\n");
return FALSE;
}
DNode* p;
p = L->next;
int j = 0;
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{
printf("查找的位序不合法!\n");
return FALSE;
}
return p;
}
双链表按值查找
//双链表按值查找
int LocateDNode(DLinkList L, DataType e)
{
int i = 1;
DNode* p;
p = L->next;
while (p != NULL && p->data != e)
{
i++;
p = p->next;
}
if (p == NULL)
{
printf("双链表中没有值为%d的元素\n", e);
return FALSE;
}
else
return i;
}
带头节点求双向链表的长度
//带头节点求双向链表的长度
int Length(DLinkList L)
{
int i = 1;
DNode* p;
p = L;
while (p != NULL)
{
p = p->next;
i++;
}
return i-1;
}
显示双链表所有结点
//显示双链表所有结点
void OutPut(DLinkList L)
{
DNode* p;
p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
菜单
//菜单
void menu(void)
{
printf("\n------------------------------------\n");
printf(" 欢迎使用双向链表操作演示!\n");
printf(" 1、双向链表初始化\n");
printf(" 2、创建双向链表\n");
printf(" 3、获取双向链表的长度\n");
printf(" 4、向双向链表插入结点\n");
printf(" 5、按值查找结点\n");
printf(" 6、按下标查找结点\n");
printf(" 7、按下标删除结点\n");
printf(" 8、退出操作演示!\n");
printf("------------------------------------\n");
}
主函数
int main(void)
{
DLinkList L=0;
DNode* p;
int n;
int e;
int i;
while (1)
{
menu();
printf("请选择想要进行的操作:");
scanf("%d", &n);
switch (n)
{
case 1: printf("双向链表初始化已完成!\n"); InitDLinkList(L); break;
case 2:printf("请输入结点的值,输入9999结束建立\n"); DList_TailInsert(L); OutPut(L); break;
case 3:printf("单链表的长度为:%d", Length(L)); break;
case 4:printf("请输入需要插入的位置和数值:"); scanf("%d%d", &i, &e); InsertDLink(L, i, e); OutPut(L); break;
case 5:printf("请输入需要查找结点的值:"); scanf("%d", &e);i= LocateDNode(L, e);
if (i == 0) { printf("没有找到!\n"); }
else { printf("找到了,下表是:%d\n", i); }break;
case 6:printf("请输入需要查找的结点的下标:"); scanf("%d", &e);p= GetElem(L, e);
if (p == NULL) { printf("没有找到!\n"); }
else printf("找到了,值为:%d\n", p->data); break;
case 7:printf("请输入需要删除的结点下标:"); scanf("%d", &e); p = GetElem(L, e); DeleteDNode(p); OutPut(L); break;
case 8:printf("已退出操作演示!\n"); break;
default:printf("输入不正确,请重新输入!\n");
}
if (n == 8)
break;
}
return 0;
}
效果展示
感谢观看!码字不易,如果本篇文章对您有帮助,麻烦点赞支持一下!!!感谢^_^!!