单链表只能从头结点开始访问链表中的数据元素,如果需要逆序访问单链表中的数据元素将极其低效。双链表是链表的一种,由节点组成,每个数据结点中都有两个指针,分别指向直接后继和直接前驱,带有游标的双向链表可以应用在某些特殊的场景。
本次例子中带有游标的双向线性链表类似Linux内核链表,利用地址重叠的特性,它可以轻松的被不同的业务节点包围,业务节点可大可小,突破了传统节点业务单一的局限。详细讲解参照https://www.bilibili.com/video/av27904891/?p=1
本次使用工具为vs2017,作者水平有限,若有问题请指出。
双向链表头文件代码:Two-way_List_C.h
#pragma once
//链表节点
typedef struct ListNode
{
struct ListNode *Next;
struct ListNode *Pre;
}ListNode;
//链表头
typedef struct ListHead
{
ListNode Head;
ListNode Cursor;
int ListLen;
}ListHead;
typedef void _ListNode;
typedef void _ListHead;
//创建双向线性表
_ListHead *CreateList();
//销毁双向链表
int DestoryList(_ListHead **Head);
//头部插入数据节点
int InsertListFront(_ListHead *Head, _ListNode *data);
//尾部插入链表
int InsertListBack(_ListHead *Head, _ListNode *data);
//任意位置插入链表
int InsertList(_ListHead *Head, _ListNode *data, int index);
//删除指定位置的链表元素
int DeleteNode(_ListHead *Head, int index);
//获取链表指定位置的元素
_ListNode *GetListNode(_ListHead *Head, int index);
//获取链表的长度
int GetListLen(_ListHead *Head);
//游标复位
int CursorReset(_ListHead *Head);
//游标下移动
int CursorMoveNext(_ListHead *Head);
//游标上移动
int CursorMovePre(_ListHead *Head);
//获取当前游标的元素
_ListNode *GetCurrentCursor(_ListHead *Head);
//根据传来的节点数据删除节点
int Delete_From_Node(_ListHead *Head, _ListNode *data);
双向链表头函数实现代码:Two-way_List_C.cpp
# include"pch.h"
# include"Two-way_List_C.h"
# include"stdio.h"
# include"stdlib.h"
//创建双向线性表
_ListHead *CreateList()
{
//开辟头指针空间
ListHead *Head = (ListHead *)malloc(sizeof(ListHead));
if (Head == NULL)
{
printf("Malloc List Head Error :CreateList() \n");
return NULL;
}
Head->Head.Next = NULL;
Head->Head.Pre = NULL;
Head->Cursor.Next = NULL;
Head->Cursor.Pre = NULL;
Head->ListLen = 0;
return Head;
}
//销毁双向链表
int DestoryList(_ListHead **Head)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error :DestoryList() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)*Head; //类型转换
//清空所有指向
header->Head.Next = NULL;
header->Head.Pre = NULL;
header->Cursor.Next = NULL;
header->Cursor.Pre = NULL;
header->ListLen = 0;
*Head = NULL;
free(header);
return ret;
}
//头部插入数据节点
int InsertListFront(_ListHead *Head, _ListNode *data)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error || data == NULL :InsertListFront() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
ListNode *datanode = (ListNode *)data; //类型转换
if (header->ListLen == 0) //链表中还没有数据
{
header->Head.Next = datanode;
datanode->Next = NULL; //后继指向NULL
datanode->Pre = NULL; //前驱指向NULL
header->ListLen++;
}
else
{
header->Head.Next->Pre = datanode; //0号位置前驱指向待插入节点
datanode->Next = header->Head.Next; //待插入节点的后继指向0号结点
datanode->Pre = NULL; //前驱指向NULL
header->Head.Next = datanode; //头节点的指向待插入节点
header->ListLen++;
}
return ret;
}
//尾部插入链表
int InsertListBack(_ListHead *Head,_ListNode *data)
{
int ret = 0;
if (Head == NULL || data == NULL)
{
printf("Parameters Error :InsertListBack() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
ListNode *datanode = (ListNode *)data; //类型转换
ListNode *current = header->Head.Next; //current指向0号几点
if (header->ListLen == 0) //链表中还没有数据
{
header->Head.Next = datanode;
datanode->Next = NULL; //后继指向NULL
datanode->Pre = NULL; //前驱指向NULL
header->ListLen++;
}
else
{
for (int i=0; i<header->ListLen-1; i++) //移动完之后current指向末尾元素
{
current = current->Next;
}
datanode->Pre = current; //待插入节点指向末尾节点
current->Next = datanode; //末尾节点指向待插入节点
datanode->Next = NULL;
header->ListLen++;
}
return ret;
}
//任意位置插入链表
int InsertList(_ListHead *Head, _ListNode *data, int index)
{
int ret = 0;
if (Head == NULL || data == NULL)
{
printf("Parameters Error :InsertList() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
ListNode *datanode = (ListNode *)data; //类型转换
ListNode *current = header->Head.Next; //current指向0号几点
ListNode *temp = NULL; //临时指针变量
if (index < 0 || index > header->ListLen)
{
printf("Insert Index Error :InsertList() \n");
ret = -1;
return ret;
}
if (header->ListLen == 0) //链表中还没有数据
{
header->Head.Next = datanode;
datanode->Next = NULL; //后继指向NULL
datanode->Pre = NULL; //前驱指向NULL
header->ListLen++;
}
else
{
for (int i = 0; i < index - 1; i++) //移动完之后current指向带插入节点的前一个
{
current = current->Next;
}
if (index == 0) //插在0号位置
{
header->Head.Next->Pre = datanode; //0号位置前驱指向待插入节点
datanode->Next = header->Head.Next; //待插入节点的后继指向0号结点
header->Head.Next = datanode; //头节点的指向待插入节点
datanode->Pre = NULL;
header->ListLen++;
}
else if (index == header->ListLen) //插在最后一个节点
{
datanode->Pre = current; //待插入节点指向末尾节点
current->Next = datanode; //末尾节点指向待插入节点
datanode->Next = NULL;
header->ListLen++;
}
else
{
temp = current->Next; //temp指向待插入元素的下一个
temp->Pre = datanode;
datanode->Next = temp;
current->Next = datanode;
datanode->Pre = current;
header->ListLen++;
}
}
return ret;
}
//删除指定位置的链表元素
int DeleteNode(_ListHead *Head, int index)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error :DeleteNode() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
ListNode *current = header->Head.Next; //current指向0号几点
ListNode *temp = NULL; //临时指针变量
if (index < 0 || index > header->ListLen-1)
{
printf("Insert Index Error :DeleteNode() \n");
ret = -1;
return ret;
}
if (header->ListLen == 0) //链表中还没有数据
{
printf("List is empty :DeleteNode() \n");
ret = -1;
return ret;
}
else
{
for (int i = 0; i < index-1; i++) //移动完之后current指向带插入节点的前一个
{
current = current->Next;
}
if (index == 0) //删除的是首节点
{
temp = header->Head.Next->Next; //temp指向1号元素
temp->Pre = NULL;
header->Head.Next = temp; //头节点指向1号位置
header->Cursor.Next = temp;
header->Cursor.Pre = NULL; //游标前驱指向null
header->ListLen--;
}
else if (index == header->ListLen-1) //删除的是最后一个节点
{
current->Next = NULL;
header->ListLen--;
header->Cursor.Next = current;
header->Cursor.Pre = current->Pre;
}
else //删除的节点非头尾节点
{
temp = current->Next->Next; //temp指向待删除节点的后一个节点
current->Next = temp;
temp->Pre = current;
//设置游标
header->Cursor.Next = temp;
header->Cursor.Pre = current;
header->ListLen--;
}
}
return ret;
}
//获取链表指定位置的元素
_ListNode *GetListNode(_ListHead *Head, int index)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error :GetListNode() \n");
return NULL;
}
ListHead *header = (ListHead *)Head; //类型转换
ListNode *current = header->Head.Next; //current指向0号几点
ListNode *temp = NULL; //临时指针变量
if (index < 0 || index > header->ListLen)
{
printf("Index Error :GetListNode() \n");
return NULL;
}
if (header->ListLen == 0) //链表中还没有数据
{
return NULL;
}
else
{
if (index == 0)
{
return current;
}
else
{
for (int i = 0; i < index - 1; i++) //移动到待获取位置的前面
{
current = current->Next;
}
return current->Next;
}
}
}
//获取链表的长度
int GetListLen(_ListHead *Head)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error :GetListLen() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
return header->ListLen;
}
//游标复位
int CursorReset(_ListHead *Head)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error :CursorReset() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
header->Cursor.Next = header->Head.Next;
header->Cursor.Pre = NULL;
return ret;
}
//游标下移动
int CursorMoveNext(_ListHead *Head)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error :CursorMoveNext() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
ListNode *current = header->Head.Next; //current指向0号几点
ListNode *temp = NULL; //临时指针变量
if (header->Cursor.Next->Next == NULL) //当前节点是最后一个节点
{
printf("\n Cursor is in the end point \n");
}
else
{
temp = header->Cursor.Next; //temp=当前游标节点位置
header->Cursor.Pre = temp; //游标的上一个节点 = 当前游标节点位置
header->Cursor.Next = temp->Next; //游标的下一个节点 = 当前游标节点的下一个位置
}
return ret;
}
//游标上移动
int CursorMovePre(_ListHead *Head)
{
int ret = 0;
if (Head == NULL)
{
printf("Parameters Error :CursorMoveNext() \n");
ret = -1;
return ret;
}
ListHead *header = (ListHead *)Head; //类型转换
ListNode *current = header->Head.Next; //current指向0号几点
ListNode *temp = NULL; //临时指针变量
if (header->Cursor.Pre == NULL)
{
printf("\n Cursor is in the start point \n");
}
else
{
temp = header->Cursor.Next; //temp=当前游标节点位置
header->Cursor.Next = temp->Pre;
header->Cursor.Pre = temp->Pre->Pre;
}
return ret;
}
//获取当前游标的元素
_ListNode *GetCurrentCursor(_ListHead *Head)
{
if (Head == NULL)
{
printf("Parameters Error :GetCurrentCursor() \n");
return NULL;
}
ListHead *header = (ListHead *)Head; //类型转换
//链表为空
if (header->Head.Next == 0)
{
printf("List is empty");
return NULL;
}
return header->Cursor.Next; //返回当前前游标
}
//根据传来的节点数据删除节点
int Delete_From_Node(_ListHead *Head, _ListNode *data)
{
int ret = 0;
int tag = 0;
int i = 0;
//防爆
if (Head == NULL || data == NULL)
{
printf("Link list is not exist or data node is empty:Delete_From_Node() \n");
ret = -1;
return ret;
}
//数据转换
ListHead *header = (ListHead *)Head; //类型转换
ListNode *datanode = (ListNode *)data; //类型转换
ListNode *current = header->Head.Next; //current指向0号几点
for (i = 0; i < header->ListLen; i++) //循环玩之后在cuurrent在最后一个位置
{
if (current == datanode)
{
tag = 1;
break;
}
current = current->Next;
}
if (tag == 1)
{
DeleteNode(header,i); //删除元素
}
else
{
printf("\n can't find element to delete \n");
}
return ret;
}
测试链表功能函数:Two-way_List_Test_C.cpp
# include"pch.h"
# include"Two-way_List_C.h"
# include"stdio.h"
# include"stdlib.h"
typedef struct person
{
ListNode node;
int age;
}person;
//打印数据
void Printf_List(_ListHead * Head)
{
ListHead *header = (ListHead *)Head; //类型转换
person *pp = NULL;
printf("\n----------------开始打印数据-------------------\n");
for (int i=0; i<header->ListLen; i++)
{
pp = (person *)GetListNode(Head, i);
printf("%d ",pp->age);
}
printf("\n----------------结束打印数据-------------------\n");
}
//打印游标上下移,获取游标
void Printf_Cursor_Move(_ListHead * Head)
{
ListHead *header = (ListHead *)Head; //类型转换
person *pp = NULL;
printf("测试游标下移功能 \n");
pp = (person*)GetCurrentCursor(Head);
printf("%d ",pp->age);
CursorMoveNext(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
CursorMoveNext(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
CursorMoveNext(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
CursorMoveNext(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
printf("\n 测试游标上移功能 \n");
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
CursorMovePre(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
CursorMovePre(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
CursorMovePre(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
CursorMovePre(Head);
pp = (person*)GetCurrentCursor(Head);
printf("%d ", pp->age);
}
void test()
{
person p1, p2, p3, p4, p5, p6, p7;
p1.age = 31;
p2.age = 32;
p3.age = 33;
p4.age = 34;
p5.age = 35;
p6.age = 36;
p7.age = 37;
_ListHead * head = CreateList();
//测试插入数据
printf("测试链表插入功能 \n");
InsertListFront(head, &p1);
InsertListFront(head, &p2);
InsertListBack(head, &p3);
InsertListBack(head, &p4);
Printf_List(head);
InsertList(head, &p5,4);
InsertList(head, &p6, 0);
InsertList(head, &p7, 2);
Printf_List(head);
//测试删除数据
printf("测试链表删除功能 \n");
DeleteNode(head, 0);
Printf_List(head);
DeleteNode(head, 1);
Printf_List(head);
DeleteNode(head, 4);
Printf_List(head);
//测试游标上下移,获取当前游标,游标复位功能
CursorReset(head); //游标复位
Printf_Cursor_Move(head);
//测试根据元素删除该元素
Delete_From_Node(head, &p1);
Printf_List(head);
//销毁链表
DestoryList(&head);
InsertListFront(head, &p1);
}
int main()
{
test();
system("pause");
return 0;
}