【数据结构】双向链表


1.双向链表的结构

typedef int LTDataType;
typedef struct ListNode
{
	LTDataType data;
	struct ListNode* next;//记录下一个结点的地址
	struct ListNode* prev;//记录上一个结点的地址
}ListNode;

在这里插入图片描述

2.双向链表的基本操作

2.1创建返回链表的头结点

这里所说的头结点就是哨兵位头结点(不存放有效数据)。因为后面可能还要申请结点,所以多写一个函数来申请结点。
代码

//动态申请一个结点.
ListNode* BuyListNode(LTDataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("malloc");
		return NULL;
	}
	newnode->data = x;
	newnode->prev = NULL;
	newnode->next = NULL;
	return newnode;
}
// 创建返回链表的头结点.
ListNode* ListCreate()
{
	ListNode* head = BuyListNode(-1);//随便传个有效数据即可
	head->next = head;
	head->prev = head;
	return head;
}

2.2双向链表尾插

// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
	ListNode* tail = pHead->prev;
	ListNode* newnode = BuyListNode(x);
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = pHead;
	pHead->prev = newnode;
}

2.3双向链表打印

void ListPrint(ListNode* pHead)
{
	assert(pHead);
	ListNode* cur = pHead->next;
	printf("<=head=>");
	while (cur != pHead)
	{
		printf("%d<=>", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

在这里说下,为什么一些指针有必要断言,一些没必要?如果一个指针可以是NULL,也可以不是NULL,此时不用断言,比如我们传一个空链表给尾插函数,就可以断言,因为我们要插入元素。如果一个指针不可能为NULL,这时就得断言,可以有效地防止一些错误,比如不小心传NULL给函数。

2.4双向链表尾插

bool LTempty(ListNode* pHead)
{
	return pHead->next == pHead;//为真,返回1,为假,返回0
}
void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	assert(!LTempty(pHead));
	ListNode* Tail = pHead->prev;
	ListNode* PrevTail = pHead->prev->prev;
	pHead->prev = PrevTail;
	PrevTail->next = pHead;
	free(Tail);
	Tail = NULL;
}

2.5双向链表头插

void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* newnode = BuyListNode(x);
	newnode->next = pHead->next;
	pHead->prev = newnode;
	newnode->prev = pHead;
	pHead->next = newnode;
}

2.6双向链表头删

void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	assert(!LTempty(pHead));
	ListNode* First = pHead->next;
	ListNode* NextFirst = First->next;
	pHead->next = NextFirst;
	NextFirst->prev = pHead;
	free(First);
	First = NULL;
}

2.7双向链表查找

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;
}

2.8双向链表在pos的前面进行插入

void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* newnode = BuyListNode(x);
	ListNode* PrevPos = pos->prev;
	newnode->next = pos;
	pos->prev = newnode;
	PrevPos->next = newnode;
	newnode->prev = PrevPos;
}

2.9双向链表删除pos位置的节点

void ListErase(ListNode* pos)
{
	assert(pos);
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;
	free(pos);
	pos = NULL;
}

2.10双向链表销毁

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;
}

3.测试

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值