数据结构:线性表链式存储结构(双向链表) C语言版

双向链表:

在单链表中,有了 next 指针,这使得查找下一结点的时间复杂度为 O ( 1 ) O(1) O(1) ,可是如果我们查找上一结点的话,那最坏的时间复杂度就是 O ( n ) O(n) O(n) 了,因为每次都要从头开始遍历查找。
双向链表就克服了这一缺陷。双向链表 ( Double Linked List ) 是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。 所以,在双向链表中的结点都有两个指针域,一个指向直接后继,了另一个指向直接前驱。

typedef struct _Tag_D_LinkList_Node
{
	struct _Tag_D_LinkList_Node* next; //后继
	struct _Tag_D_LinkList_Node* prec; //前驱
}DLTNode;							   //双向链表节点

既然单链表有循环链表,双向链表也可以有循环双向链表。
包含头节点的双向循环空链表,其结构如下图:
在这里插入图片描述
非空的双向循环链表带头结点的结构如下图:
在这里插入图片描述

双向链表的代码设置与实现:

在这里插入图片描述

基于 liunx 内核链表模型

1:头文件 ,定义数据结构和操作函数

#ifndef  _D_LINK_LIST_H_
#define  _D_LINK_LIST_H_


#define  DLINK_LIST_ERR_POS   (DLINK_LIST_ERROR-2)    //位置下标超出范围 
#define  DLINK_LIST_ERR_NULL  (DLINK_LIST_ERROR-1)    //数据或参数为空
#define  DLINK_LIST_ERROR     (-1)                    //错误
#define  DLINK_LIST_VALID     (DLINK_LIST_ERROR+1)    //正确



typedef void DLinkList;

typedef struct _Tag_D_LinkList_Node
{
	struct _Tag_D_LinkList_Node* next; //后继
	struct _Tag_D_LinkList_Node* prec; //前驱
}DLTNode;							   //双向链表节点

//创建链表
DLinkList* DLinkList_Create();

//释放链表指针空间
void DLinkList_Destroy(DLinkList* list);

//清空链表
void DLinkList_Clear(DLinkList* list);

//获取链表元素个数
int DLinkList_Length(DLinkList* list);

//根据给定位置下标插入元素
int DLinkList_Insert(DLinkList* list, DLTNode* node, int pos);

//根据给定位置获取元素节点
DLTNode* DLinkList_Get(DLinkList* list, int pos);

//根据给定位置删除元素节点
DLTNode* DLinkList_Delete(DLinkList* list, int pos);

//删除指定的元素节点
DLTNode* DLinkList_DeleteNode(DLinkList* list, DLTNode* node);

//重置链表
DLTNode* DLinkList_Reset(DLinkList* list);

//获取当前链表游标指向元素
DLTNode* DLinkList_Current(DLinkList* list);

//获取当前链表游标指向元素的下一个元素
DLTNode* DLinkList_Next(DLinkList* list);

//获取当前链表游标指向元素的上一个元素
DLTNode* DLinkList_Pre(DLinkList* list);

#endif //_D_LINK_LIST_H_

2:函数实现:

#include "DLinkList.h"
#include <stdlib.h>
#include<memory.h>

typedef struct _Tag_DLink_List
{
	DLTNode 	pHeader;     //链表头指针
	DLTNode*	slider;      //链表游标
	int			length;      //链表数据长度
}TDList;					 //链表内部数据结构	


//创建链表
DLinkList* DLinkList_Create()
{
	TDList* pdList = (TDList*)malloc(sizeof(TDList));
	if (pdList!=NULL)
	{
		memset(pdList, 0x00, sizeof(TDList));
		pdList->length = 0;
		pdList->pHeader.next = NULL;
		pdList->pHeader.prec = NULL;
		pdList->slider = NULL;
	}
	return pdList;
}

//释放链表指针空间
void DLinkList_Destroy(DLinkList* list)
{
	if (list!=NULL)
	{
		free(list);
	}
}

//清空链表
void DLinkList_Clear(DLinkList* list)
{
	TDList* pdList = (TDList*)list;
	if (pdList!=NULL)
	{
		pdList->length = 0;
		pdList->slider = NULL;
		pdList->pHeader.next = NULL;
		pdList->pHeader.prec = NULL;
	}
	return ;
}

//获取链表元素个数
int DLinkList_Length(DLinkList* list)
{
	TDList* pdList = (TDList*)list;
	if (pdList==NULL)
	{
		return DLINK_LIST_ERROR;
	}
	return pdList->length;
}

//根据给定位置下标插入元素
int DLinkList_Insert(DLinkList* list, DLTNode* node, int pos)
{
	int		i = 0;
	TDList* pdList = (TDList*)list;
	if (pdList == NULL || node == NULL)
	{
		return DLINK_LIST_ERR_NULL;
	}
	if (pos < 0)
	{
		return DLINK_LIST_ERR_POS;
	}

	//声明辅助指针变量
	DLTNode* currNode = (DLTNode*)pdList; //指针指向链表头部
	DLTNode* nextNode = NULL;
	{
		
		for (i = 0; i < pos && (currNode->next != NULL); i++)
		{
			currNode = currNode->next;//指针移动到指定位置
		}
		nextNode = currNode->next;//当前位置的元素
		//交换位置
		currNode->next = node;//插入当前节点
		node->next = nextNode;//要插入的元素节点的后继指针指向原来位置的节点 

		//nextNode==NULL表示当前链表插入第一个元素 要特殊处理,如果不是则让后续元素的前驱指针指向当前插入元素
		if (nextNode !=NULL)
		{
			nextNode->prec = node;//前驱指向要插入的元素
		}

		if (pdList->length == 0)
		{
			pdList->slider = node;
		}

		if (currNode == (DLTNode*)pdList)//当前在0号位置插入元素
		{
			node->prec = NULL;
		}
		else
		{
			node->prec = currNode;
		}
		pdList->length++;
	}
	return DLINK_LIST_VALID;
}

//根据给定下标位置获取元素节点
DLTNode* DLinkList_Get(DLinkList* list, int pos)
{
	TDList* pdList = (TDList*)list;
	DLTNode* ret = NULL;
	int i = 0;
	if (pdList != NULL && 0 <= pos&&pos < pdList->length);
	{
		DLTNode* currTmp = (DLTNode*)pdList;
		for (i = 0; i < pos;i++)
		{
			currTmp = currTmp->next;
		}
		ret = currTmp->next;
	}
	return ret;
}

//根据给定位置删除元素节点
DLTNode* DLinkList_Delete(DLinkList* list, int pos)
{
	TDList  *pdList = (TDList*)list;
	DLTNode *ret = NULL, *next = NULL;
	int i = 0;
	if (pdList==NULL||pos<0)
	{
		return NULL;
	}

	DLTNode* currTmp = (DLTNode*)pdList;
	for (i = 0; i < pos;i++)
	{
		currTmp = currTmp->next;
	}
	ret = currTmp->next;//要删除的节点
	next = ret->next;//删除节点的下一节点

	currTmp->next = next;//1:跳过删除的节点,后驱指针进行链表连接
	if (next!=NULL)//2:前驱指针进行连接
	{
		next->prec = currTmp;
		if (currTmp == (DLTNode*)pdList)//如果是头节点,前驱指针指向NULL
		{
			next->prec = NULL;
		}
	}

	if (pdList->slider==ret)
	{
		pdList->slider = next;
	}
	pdList->length--;

	return ret;
}

//删除指定的元素节点
DLTNode* DLinkList_DeleteNode(DLinkList* list, DLTNode* node)
{
	TDList* pdList = (TDList*)list;
	DLTNode* ret = NULL;
	int i = 0;
	if (pdList!=NULL&&node!=NULL)
	{
		DLTNode *currTmp = (DLTNode*)pdList;
		for (i = 0; i < pdList->length; i++)
		{
			if (currTmp->next=node)
			{
				ret = currTmp->next;
				break;
			}
			currTmp = currTmp->next;
		}
		if (ret!=NULL)
		{
			DLinkList_Delete(pdList, i);
		}
	}

	return ret;
}

//重置链表游标
DLTNode* DLinkList_Reset(DLinkList* list)
{
	TDList* pdList = (TDList*)list;
	DLTNode* ret = NULL;
	if (pdList!=NULL)
	{
		pdList->slider = pdList->pHeader.next;
		ret = pdList->slider;
	}
	return ret;
}

//获取当前链表游标指向元素
DLTNode* DLinkList_Current(DLinkList* list)
{
	TDList* pdList = (TDList*)list;
	DLTNode* ret = NULL;
	if (pdList!=NULL)
	{
		ret = pdList->slider;
	}
	return ret;
}

//获取当前链表游标指向的元素并且游标下移指向下一个元素
DLTNode* DLinkList_Next(DLinkList* list)
{
	TDList* pdList = (TDList*)list;
	DLTNode* ret = NULL;
	if (pdList != NULL&&pdList->slider!=NULL)
	{
		ret = pdList->slider;
		pdList->slider = ret->next;
	}
	return ret;
}

//获取当前链表游标指向的元素并且游标上移指向上一个元素
DLTNode* DLinkList_Pre(DLinkList* list)
{
	TDList* pdList = (TDList*)list;
	DLTNode* ret = NULL;
	if (pdList != NULL&&pdList->slider != NULL)
	{
		ret = pdList->slider;
		pdList->slider = ret->prec;
	}
	return ret;
}

函数重点操作:
插入操作:

在这里插入图片描述
删除操作:

在这里插入图片描述
3:调用示例:

#define  _CRT_SECURE_NO_WARNINGS
#include "DLinkList.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct _User_info
{
	DLTNode node;
	int age;
	char name[16];
}User;

int main(int argc, char *argv[])
{
	int i = 0;
	User *tmp = NULL;
	DLinkList* list = DLinkList_Create();

	User u1, u2, u3, u4, u5, u6;
	{
		u1.age = 11;
		u2.age = 12;
		u3.age = 13;
		u4.age = 14;
		u5.age = 15;
		u6.age = 16;
		strcpy(u1.name, "AAAA");
		strcpy(u2.name, "BBBB");
		strcpy(u3.name, "CCCC");
		strcpy(u4.name, "DDDD");
		strcpy(u5.name, "EEEE");
		strcpy(u6.name, "FFFF");
	}

	//插入数据
	DLinkList_Insert(list, (DLTNode*)&u1, DLinkList_Length(list));
	DLinkList_Insert(list, (DLTNode*)&u2, DLinkList_Length(list));
	DLinkList_Insert(list, (DLTNode*)&u3, DLinkList_Length(list));
	DLinkList_Insert(list, (DLTNode*)&u4, DLinkList_Length(list));
	DLinkList_Insert(list, (DLTNode*)&u5, DLinkList_Length(list));
	DLinkList_Insert(list, (DLTNode*)&u6, DLinkList_Length(list));

	for (i = 0; i < DLinkList_Length(list); i++)
	{
		tmp = (User *)DLinkList_Get(list, i);
		if (tmp==NULL)
		{
			printf("获取元素失败\n");
			break;
		}
		printf("age=%d ; name=%s \n", tmp->age, tmp->name);
	}

	DLinkList_Reset(list); //重置链表游标
	DLinkList_Next(list);//链表游标下移

	tmp =(User*) DLinkList_Current(list);
	printf("age=%d ; name=%s \n", tmp->age, tmp->name);

	DLinkList_Pre(list); //链表游标上移
	tmp = (User*)DLinkList_Current(list);
	printf("age=%d ; name=%s \n", tmp->age, tmp->name);

	printf("list count=%d \n", DLinkList_Length(list));

	DLinkList_Destroy(list);

	system("pause");
}

输出:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值