双向链表的接口实现(附图解和源码)
文章目录
- 双向链表的接口实现(附图解和源码)
- 前言
- 一、定义结构体
- 二、接口实现(附图解+源码)
- 1.初始化双向链表
- 2.开辟新空间
- 3.尾插数据
- 4.尾删数据
- 5.打印双向链表中数据
- 6.头插数据
- 7.头删数据
- 8.查找结点位置
- 9.在pos位置之前插入
- 10.删除pos位置
- 11.销毁双向链表
- 三、源代码展示
- 1.test.c(测试+主函数)
- 2.List.h(接口函数的声明)
- 3.List.c(接口函数的实现)
- 总结
前言
本文主要介绍双向链表中增删查改等接口实现,结尾附总源码!
一、定义结构体
代码如下(示例):
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* prev;
struct ListNode* next;
}ListNode;
二、接口实现(附图解+源码)
这里一共10个接口,我会我都会一 一为大家讲解(图解+源码)
1.初始化双向链表
初始化出一个哨兵位的头结点(用malloc开辟),next和prev都指向自己。具体如下图!
代码如下(示例):
ListNode* ListInit()
{
ListNode* p = (ListNode*)malloc(sizeof(ListNode));
if (p == NULL)
{
perror(errno);
}
ListNode* phead = p;
phead->next = phead;
phead->prev = phead;
return phead;
}
2.开辟新空间
(1)开辟一个链表类型的动态空间,将地址给newnode;
(2)将值放入 newnode 的 data 数据内;
(3)将 newnode 的 next 和 prev 都置为NULL;
注意:1.将malloc开辟空间存到 newnode 里面时,参数为结构体所占的字节大小!2.对 newnode 进行 NULL 判断!
代码如下(示例):
ListNode* BuyListNode(LTDataType x)
{
ListNode* p = (ListNode*)malloc(sizeof(ListNode));
if (p == NULL)
{
perror(errno);
}
ListNode* newNode = p;
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
3.尾插数据
代码如下(示例):
void ListPushBack(ListNode* phead, LTDataType x)//尾插数据
{
ListNode* tail = phead->prev;
ListNode* newnode = BuyListNode(x);
//第一个链接
tail->next = newnode;
newnode->prev = tail;
//第二个链接
phead->prev = newnode;
newnode->next = phead;
}
4.尾删数据
这里需要两次进行断言:
代码如下(示例):
void ListPopBack(ListNode* phead)//尾删
{
assert(phead);
assert(phead->next != phead);
ListNode* tail = phead->prev;
ListNode* tailprev = tail->prev;
free(tail);
//连接
tailprev->next = phead;
phead->prev = tailprev;
}
5.打印双向链表中数据
代码如下(示例):
void ListPrint(ListNode* phead)//打印数据
{
assert(phead);
ListNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
6.头插数据
头插数据也是很简单的一个接口,链接两次即可,如下图!
代码如下(示例):
void ListPushFront(ListNode* phead, LTDataType x)//头插
{
assert(phead);
ListNode* newNode = BuyListNode(x);
ListNode* next = phead->next;
phead->next = newNode;
newNode->prev = phead;
newNode->next = next;
next->prev = newNode;
}
7.头删数据
在头删数据时和尾删数据一样都需要进行两次断言!如下图!
代码如下(示例):
void ListPopFront(ListNode* phead)//头删
{
assert(phead);
assert(phead->next != phead);
ListNode* next = phead->next;
ListNode* nextNext = next->next;
phead->next = nextNext;
nextNext->prev = phead;
free(next);
}
8.查找结点位置
这个比较简单,和单链表一样,直接用cur遍历即可,直接上代码:
代码如下(示例):
ListNode* ListFind(ListNode* phead, LTDataType x)
{
assert(phead);
ListNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
9.在pos位置之前插入
代码如下(示例):
void ListInsert(ListNode* pos, LTDataType x)//pos位置之前插入
{
assert(pos);
ListNode* newNode = BuyListNode(x);
ListNode* posPrev = pos->prev;
// posPrev newnode pos
posPrev->next = newNode;
newNode->prev = posPrev;
newNode->next = pos;
pos->prev = newNode;
}
根据ListInsert接口我们可以把头插和尾插进行改版,如下图!
10.删除pos位置
代码如下(示例):
void ListErase(ListNode* pos)//删除pos位置
{
assert(pos);
ListNode* prev = pos->prev;
ListNode* next = pos->next;
free(pos);
pos = NULL;
prev->next = next;
next->prev = prev;
}
11.销毁双向链表
代码如下(示例):
void ListDestory(ListNode* phead)
{
assert(phead);
ListNode* cur = phead->next;
while (cur != phead)
{
ListNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
phead = NULL;
}
三、源代码展示
1.test.c(测试+主函数)
代码如下(示例):
#include "list.h"
void Testlist1()
{
ListNode* n1 = ListInit();
ListPushBack(n1, 1);//尾插
ListPushBack(n1, 2);//尾插
//ListPushBack(n1, 3);//尾插
//ListPushBack(n1, 4);//尾插
//ListPushBack(n1, 5);//尾插
//ListPopFront(n1);//头删
//ListPopBack(n1);//尾删
//ListPushFront(n1, 0);//头插
ListPrint(n1);
}
void Testlist2()
{
ListNode* n1 = ListInit();
ListPushBack(n1, 1);//尾插
ListPushBack(n1, 2);//尾插
ListPushBack(n1, 3);//尾插
ListPushBack(n1, 4);//尾插
ListPushBack(n1, 5);//尾插
ListNode* p = ListFind(n1, 5);
printf("%d \n", p->data);
}
void Testlist3()
{
ListNode* n1 = ListInit();
ListPushBack(n1, 1);//尾插
ListPushBack(n1, 2);//尾插
ListPushBack(n1, 3);//尾插
ListPushBack(n1, 4);//尾插
ListPushBack(n1, 5);//尾插
//ListNode* p = ListFind(n1, 5);
//ListInsert(p, 0);
ListDestory(n1);
ListPrint(n1);
}
int main()
{
//Testlist1();
//Testlist2();
Testlist3();
return 0;
}
2.List.h(接口函数的声明)
代码如下(示例):
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* prev;
struct ListNode* next;
}ListNode;
ListNode* ListInit();//初始化双向链表
void ListPushBack(ListNode* phead, LTDataType x);//尾插
void ListPopBack(ListNode* phead);//尾删
void ListPushFront(ListNode* phead, LTDataType x);//头插
void ListPopFront(ListNode* phead);//头删
void ListPrint(ListNode* phead);//打印
ListNode* ListFind(ListNode* phead, LTDataType x);//查找数据
void ListInsert(ListNode* pos, LTDataType x);//pos位置之前插入
void ListErase(ListNode* pos);//删除pos位置
void ListDestory(ListNode* phead);//销毁双向链表
3.List.c(接口函数的实现)
代码如下(示例):
#include "list.h"
ListNode* ListInit()
{
ListNode* p = (ListNode*)malloc(sizeof(ListNode));
if (p == NULL)
{
perror(errno);
}
ListNode* phead = p;
phead->next = phead;
phead->prev = phead;
return phead;
}
ListNode* BuyListNode(LTDataType x)
{
ListNode* p = (ListNode*)malloc(sizeof(ListNode));
if (p == NULL)
{
perror(errno);
}
ListNode* newNode = p;
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
void ListPushBack(ListNode* phead, LTDataType x)//尾插数据
{
ListNode* tail = phead->prev;
ListNode* newnode = BuyListNode(x);
//第一个链接
tail->next = newnode;
newnode->prev = tail;
//第二个链接
phead->prev = newnode;
newnode->next = phead;
//ListInsert(phead, x);
}
void ListPrint(ListNode* phead)//打印数据
{
assert(phead);
ListNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
void ListPopBack(ListNode* phead)//尾删
{
assert(phead);
assert(phead->next != phead);
ListNode* tail = phead->prev;
ListNode* tailprev = tail->prev;
free(tail);
//连接
tailprev->next = phead;
phead->prev = tailprev;
}
void ListPushFront(ListNode* phead, LTDataType x)//头插
{
assert(phead);
ListNode* newNode = BuyListNode(x);
ListNode* next = phead->next;
phead->next = newNode;
newNode->prev = phead;
newNode->next = next;
next->prev = newNode;
//ListInsert(phead->next, x);
}
void ListPopFront(ListNode* phead)//头删
{
assert(phead);
assert(phead->next != phead);
ListNode* next = phead->next;
ListNode* nextNext = next->next;
phead->next = nextNext;
nextNext->prev = phead;
free(next);
}
ListNode* ListFind(ListNode* phead, LTDataType x)
{
assert(phead);
ListNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void ListInsert(ListNode* pos, LTDataType x)//pos位置之前插入
{
assert(pos);
ListNode* newNode = BuyListNode(x);
ListNode* posPrev = pos->prev;
// posPrev newnode pos
posPrev->next = newNode;
newNode->prev = posPrev;
newNode->next = pos;
pos->prev = newNode;
}
void ListErase(ListNode* pos)//删除pos位置
{
assert(pos);
ListNode* prev = pos->prev;
ListNode* next = pos->next;
free(pos);
pos = NULL;
prev->next = next;
next->prev = prev;
}
void ListDestory(ListNode* phead)
{
assert(phead);
ListNode* cur = phead->next;
while (cur != phead)
{
ListNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
phead = NULL;
}
总结
以上就是今天要讲的内容,本文介绍双向链表的接口实现(附图解和源码)。
如果我的博客对你有所帮助记得三连支持一下,感谢大家的支持!