带头+双向+循环链表

1. 带头+双向+循环链表的结构

结构:这种链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现;其次每个链表节点有前驱指针后置指针 。

带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势

 

1.1链表的设计

注:

        1.将int 重命名为为STLDataType 是为了修改储存类型时更为轻松,增加了壮硕性。

        2.next为链表下一个节点的指针,方便寻找到下一个节点。

1.2 链表所需实现功能

// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
	LTDataType _data;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;

// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

1.2 功能实现

// 创建返回链表的头结点.
ListNode* ListCreate()
{
	ListNode* newnode = (ListNode*)malloc( sizeof(ListNode) );

	newnode->_data = 0;
    //注意创建的新节点前后指针指向自己
	newnode->_next = newnode;
	newnode->_prev = newnode;
	return newnode;
}




// 双向链表销毁
void ListDestory(ListNode* pHead)
{
	ListNode* phead = pHead;
	ListNode* prev = pHead->_next;
	ListNode* after = pHead->_next;
    
    //after为空指针当作条件是为了释放最后一个节点回到哨兵位时
    //能进到这个循环将哨兵位前后指针指向自己
	while(after)
	{
		after = after->_next;
        //释放完尾节点再次进到这个循环不释放头节点。
		if(phead != prev)
			free(prev);
		prev = after;

         //进到这个循环将哨兵位前后指针指向自己
		if (phead == after)
		{
			prev->_next = pHead;
			prev->_prev = pHead;
			break;
		}
	}
}


// 双向链表打印
void ListPrint(ListNode* pHead)
{
	ListNode* phead = pHead;
	ListNode* cur = pHead->_next;

	if (pHead == cur)
	{
		printf("哨兵位");
	}
    
    //cur指针从哨兵位后一个节点打印如果下一个不是头节点则打印“<=>”
    //并前往下一个节点,如果cur到头节点则打印结束
	while (phead != cur)
	{
		printf("%d",cur->_data);
		if (cur->_next != phead)
			printf("<=>");
		cur = cur->_next;
	}
}


// 双向链表尾插
void ListPushBack(ListNode*pHead)
{
    //用哨兵位的前驱指针找到尾巴进行尾插
    //即使只剩哨兵位也不需要担心像单链表那样单独考虑空链表的情况!!
    //该结构带来的好处
	ListNode* newnode = ListCreate();
	ListNode* tail = pHead->_prev;
	newnode->_prev = tail;
	tail->_next = newnode;
	pHead->_prev = newnode;
	newnode->_next = pHead;
}


//尾删
void ListPopBack(ListNode* pHead)
{
	ListNode* end = NULL;
	end = pHead->_prev;
	pHead->_prev = end->_prev;
	end->_prev->_next = pHead;

    //只需考虑只剩哨兵位的情况
	if(pHead != end)
		free(end);
}


//头插
void ListPushFront(ListNode* pHead , LTDataType x)
{
	ListNode* frist = pHead->_next;
	ListNode* newnode = ListCreate();
	newnode->_data = x;
	newnode->_next = frist;
	frist->_prev = newnode;
	pHead->_next = newnode;
	newnode->_prev = pHead;
}


//头删
void ListPopFront(ListNode* pHead)
{
	ListNode* frist = pHead->_next;
	ListNode* after = frist->_next;
	pHead->_next = after;
	after->_prev = pHead;
	if(pHead != frist)
		free(frist);
}


//搜索节点
ListNode* ListFind(ListNode* pHead , LTDataType x)
{
	ListNode* pFind = pHead->_next;
	while (pFind != pHead)
	{
		if (pFind->_data == x)
		{
			return pFind;
		}
		pFind = pFind->_next;
	}
	return NULL;
}


//pos前插入节点
void Insert(ListNode* pos, LTDataType x)
{
	ListNode* prev= pos->_prev;
	ListNode* newnode = ListCreate();
	newnode->_data = x;
	newnode->_next = pos;
	pos->_prev = newnode;
	prev->_next = newnode;
	newnode->_prev = prev;
}


//删除pos位置节点
void ListErase(ListNode* pos)
{
	ListNode* cur = pos;
	ListNode* prev = pos->_prev;
	ListNode* after = pos->_next;
	prev->_next = after;
	after->_prev = prev;
	if(cur != prev)
		free(cur);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值