带有游标的双向线性链表(C版本)

本文深入探讨双向链表的原理与实现,包括带有游标的双向链表的特殊应用场景,如Linux内核链表。文章提供了详细的代码示例,涵盖链表的创建、销毁、插入、删除等操作,并通过一个完整的测试函数验证链表功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单链表只能从头结点开始访问链表中的数据元素,如果需要逆序访问单链表中的数据元素将极其低效。双链表是链表的一种,由节点组成,每个数据结点中都有两个指针,分别指向直接后继和直接前驱,带有游标的双向链表可以应用在某些特殊的场景。

本次例子中带有游标的双向线性链表类似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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值