首先搞清楚双向链表和单链表的区别:
双向链表比单链表多出一个指针域,保存上一个结点的地址
双向链表:和单链表相比,双向链表有两个指针域,既可以右边的结点地址(后继),也可以保存左边的结点地址(前驱)
如果是一个空的双向链表,则它的next和prior同时指向NULL即可
双向链表的结构体设计:
//双向链表结构体设计:
typedef int ELEM_TYPE;
typedef struct Dlist
{
ELEM_TYPE data;//数据域 保存有效值
struct Dlist* next;//指针域 保存下一个节点的地址(后继)
struct Dlist* prior;//指针域 保存上一个节点的地址(前驱)
}Dlist, * PDlist;
双向链表可执行函数声明:
//初始化
void Init_dlist(struct Dlist* plist);
//购买新节点
struct Dlist* BuyNode(ELEM_TYPE val);
//头插
bool Insert_head(PDlist plist, ELEM_TYPE val);
//尾插
bool Insert_tail(PDlist plist, ELEM_TYPE val);
//按位置插
bool Insert_pos(PDlist plist, int pos, ELEM_TYPE val);
//头删
bool Del_head(PDlist plist);
//尾删
bool Del_tail(PDlist plist);
//按位置删
bool Del_pos(PDlist plist, int pos);
//按值删除
bool Del_val(PDlist plist, ELEM_TYPE val);
//查找(如果值重复,返回第一次出现的节点地址)
struct Dlist* Search(PDlist plist, ELEM_TYPE val);
//判空
bool IsEmpty(PDlist plist);
//判满(链表不用实现)
//获取有效长度
int Get_length(PDlist plist);
//清空
void Clear(PDlist plist);
//销毁1
void Destroy(PDlist plist);
//销毁2
void Destroy2(PDlist plist);
//打印
void Show(PDlist plist);
1.初始化(也就是空链的情况)
void Init_dlist(struct Dlist* plist)//(排除两个野指针的风险,将其全部赋值为NULL)
{
assert(plist != NULL);
plist->next = NULL;
plist->prior = NULL;
}
2.购买新节点(插入使用)
struct Dlist* BuyNode(ELEM_TYPE val)
{
PDlist pnewnode = (PDlist)malloc(sizeof(Dlist) * 1);
assert(pnewnode != NULL);
if (NULL == pnewnode)
{
return NULL; //购买失败
}
pnewnode->data = val;
pnewnode->next = NULL;
pnewnode->prior = NULL;
return pnewnode;
}
3.头插
bool Insert_head(PDlist plist, ELEM_TYPE val)
{
assert(plist != NULL);
PDlist pnewnode = BuyNode(val);
pnewnode->next = plist->next;//3
pnewnode->prior = plist;//4
if (plist->next != NULL)//这里需要加if语句判断一下
{
plist->next->prior = pnewnode;//2
}
plist->next = pnewnode;//1
return true;
}
4.尾插
bool Insert_tail(PDlist plist, ELEM_TYPE val)
{
assert(plist != NULL);
PDlist pnewnode = BuyNode(val);//购买新节点
PDlist p = plist;
for (p; p->next != NULL; p = p->next);
//此时 for循环结束 p指向尾结点
pnewnode->next = p->next;
pnewnode->prior = p;
p->next = pnewnode;
return true;
}
5.按位置插
//按位置插
bool Insert_pos(PDlist plist, int pos, ELEM_TYPE val)
{
assert(plist != NULL);
assert(pos >= 0 && pos <= Get_length(plist));
//头部和尾部有风险, 那最开始就排除掉
if (pos == 0)
{
return Insert_head(plist, val);
}
else if (pos == Get_length(plist))
{
return Insert_tail(plist, val);
}
//此时,能执行到这里,代表头部和尾部风险全部排除掉,剩余情况就普遍情况了
//1.购买新节点
PDlist pnewnode = BuyNode(val);
PDlist p = plist;
//2.找个合适的插入位置(找一个指针p指向待插入位置的上一个节点)
for (int i = 0; i < pos; ++i)
{
p = p->next;
}//此时 for循环结束 p指向待插入位置的上一个节点
//3.插入
pnewnode->next = p->next;
pnewnode->prior = p;
p->next->prior = pnewnode;
p->next = pnewnode;
return true;
}
6.头删
bool Del_head(PDlist plist)
{
assert(plist != NULL);
//插入不需要判满 但是删除一定记得判空
if (IsEmpty(plist))
{
return false;
}
//找个指针p指向待删除节点
PDlist p = plist->next;
plist->next = p->next;
if (p->next != NULL)//代表 不仅仅只有一个有效值
{
p->next->prior = plist;
}
free(p);
return true;
}
7.尾删
bool Del_tail(PDlist plist)
{
assert(plist != NULL);
if (IsEmpty(plist))
{
return false;
}
PDlist p = plist;
for (p; p->next != NULL; p = p->next);
//此时p指向尾结点
PDlist q = plist;
assert(q->next != NULL);
for (q; q->next != p; q = q->next);
//此时q指向倒数第二个结点
//删除
q->next = p->next;
free(p);
return true;
}
8.按位置删
//按位置删(一般来说,头和尾比较危险,一开始处理掉即可)
bool Del_pos(PDlist plist, int pos)
{
assert(plist != NULL);
assert(pos >= 0 && pos < Get_length(plist));
if (IsEmpty(plist))
{
return false;
}
if (pos == 0)
{
return Del_head(plist);
}
else if (pos == Get_length(plist) - 1)
{
return Del_tail(plist);
}
PDlist q = plist;
for (int i = 0; i < pos; ++i)
{
q = q->next;
}
PDlist p = q->next;
q->next = p->next;
p->next->prior = q;
free(p);
return true;
}
9.按值删
bool Del_val(PDlist plist, ELEM_TYPE val)
{
assert(plist != NULL);
if (IsEmpty(plist))
{
return false;
}
PDlist p = Search(plist,val);
if (p == NULL)
{
return false;
}
PDlist q = plist;
for (q; q->next != p; q = q->next);//q在p的前面
q -> next = p->next;
if (p->next != NULL)
{
p->next->prior = q; // 特殊情况:如果你找的val值 在尾结点找到了 这行代码就会失败
}
free(p);
return true;
}
10.查找
//查找(如果值重复,返回第一次出现的节点地址)
struct Dlist* Search(PDlist plist, ELEM_TYPE val)
{
assert(plist != NULL);
PDlist p = plist->next;
for (p; p != NULL; p = p->next)
{
if (p->data == val)
{
return p;
}
}
return NULL;
}
11.判空,获取长度
//判空
bool IsEmpty(PDlist plist)
{
assert(plist != NULL);
return plist->next == NULL;
}
//判满(链表不用实现)
//获取有效长度
int Get_length(PDlist plist)
{
assert(plist != NULL);
int cout = 0;
for (PDlist p = plist->next; p != NULL; p = p->next)
{
cout++;
}
return cout;
}
12.清空,销毁(两种方法),打印
//清空
void Clear(PDlist plist)
{
assert(plist != NULL);
Destroy(plist);
}
//销毁1
void Destroy(PDlist plist)
{
assert(plist != NULL);
while (plist->next != NULL)
{
struct Dlist* p = plist->next;
plist->next = p->next;//这里只需要上一个节点 指向下一个节点即可
free(p);
}
plist->next = plist->prior = NULL;
}
//销毁2
void Destroy2(PDlist plist)
{
assert(plist != NULL);
struct Dlist* p = plist->next;
struct Dlist* q = NULL;
plist->next = plist->prior = NULL;
while (p != NULL)
{
q = p->next;
free(p);
p = q;
}
}
//打印
void Show(PDlist plist)
{
assert(plist != NULL);
for (PDlist p = plist->next; p != NULL; p = p->next)
{
printf("%d ", p->data);
}
printf("\n");
}
开始测试:
在主函数中测试数据
int main()
{
struct Dlist head;
Init_dlist(&head);//初始化
for (int i = 0; i < 20; i++)
{
Insert_pos(&head, i, i + 1);
}//将1到20按位置插入
Show(&head);//打印
Insert_head(&head, 100);//头插100
Insert_tail(&head, 200);//尾插200
Show(&head);//打印
printf("length = %d\n", Get_length(&head));//打印长度
Del_head(&head);//头删
Del_tail(&head);//尾删
Show(&head);//打印
printf("length = %d\n", Get_length(&head));//打印长度
Del_pos(&head, 3);//删除第三个节点
Del_val(&head, 14);//将值为14的结点删除
Show(&head);//打印
printf("length = %d\n", Get_length(&head));//打印长度
//Destroy(&head);
Destroy2(&head);//销毁,释放内存
return 0;
}
结果: