链表——双向链表 主要包括:《双向链表的完整接口实现代码及执行程序》《链表和顺序表的区别和联系》

顺序表的实现代码及接口https://blog.csdn.net/dpfxaca6/article/details/86717082
单向链表的实现代码及接口https://blog.csdn.net/dpfxaca6/article/details/89472595

《一》 双向链表

双向链表思想 : 结构最复杂,一般用在单独储存数据,实际中使用的链表数据结构,都是带头双向链表循环链表,,虽然这个链表看起来比较复杂,但是实现代码之后,这个结构可以解决很多问题,也有很多优势,实现就反而简单了。

在这里插入图片描述
下面我们就看一下代码的实现。

首先和之前一样,我们先给出实现的接口;

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<malloc.h>

typedef int LTDataType;
typedef struct ListNode
{
	LTDataType _data;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;
typedef struct List
{
	ListNode* _head;
}List;


void ListInit(List* plist);         //创建一个链表
void ListDestory(List* plist);    //消除一个链表
void ListPushBack(List* plist, LTDataType x);   //尾插
void ListPopBack(List* plist);  //尾删
void ListPushFront(List* plist, LTDataType x);   //头插
void ListPopFront(List* plist);   //头删
ListNode* ListFind(List* plist, LTDataType x); //查找
// 在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 删除pos位置的节点
void ListErase(ListNode* pos);  
void ListRemove(List* plist, LTDataType x); //移除
int ListSize(List* plist);  //节点个数
int ListEmpty(List* plist);  // 清空
void ListReverse(List* plist); //相反链表
void ListPrint(List* plist);

还是在这里说明一下,如果有想法的同学,自己还是可以实现以下的,思想很重要。

下面是我的实现代码:

#include"Slist.h"

ListNode*BuyListNode(LTDataType x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	node->_data = x;
	node->_next = NULL;
	node->_prev = NULL;
	return node;
}
void ListInit(List* plist)    //构建链表
{
	ListNode* head = BuyListNode(-1);
	assert(plist);
	head->_next = head;
	head->_prev = head;
	plist->_head = head;
}
void ListDestory(List* plist)  //判断链表
{
	ListNode* head = plist->_head;
	ListNode* cur = head->_next;
	ListNode* next = NULL;
	assert(plist);
	while (cur != head)
	{
		next = cur->_next;
		free(cur);
		cur = cur->_next;
	}
	free(head);
	head = NULL;
}
void ListPushBack(List* plist, LTDataType x)    //尾插
{
	ListNode*head = plist->_head;
	ListNode* tail = head->_prev;
	ListNode* newnode = BuyListNode(x);
	assert(plist);
	tail->_next = newnode;
	newnode->_prev = tail;
	newnode->_next = head;
	head->_prev = newnode;
}


void ListPopBack(List* plist)    //尾删
{
	ListNode*head = plist->_head;
	ListNode* tail = head->_prev;
	ListNode* tailprev = tail->_prev;
	assert(plist);
	free(tail);
	tailprev->_next = head;
	head->_prev = tailprev;

}

void ListPushFront(List* plist, LTDataType x)  //头插
{
	ListNode*head = plist->_head;
	ListNode* next = head->_next;
	ListNode* newnode = BuyListNode(x);
	assert(plist);
	head->_next = newnode;
	newnode->_next = next;
	newnode->_prev = head;
	next->_prev = newnode;
}

void ListPopFront(List* plist) //头删
{
	ListNode* head = plist->_head;
	ListNode* next = head->_next;
	ListNode* nextnext = next->_next;
	assert(plist);
	free(next);
	head->_next = nextnext;
	nextnext->_prev = head;

}


ListNode* ListFind(List* plist, LTDataType x)  //查找
{
	ListNode* head = plist->_head;
	ListNode* cur = head->_next;
	assert(plist);
	while (cur != head)
	{
		if (cur->_data == x)
		{
			return cur;
		}
		cur = cur->_next;
	}
	return cur;
}
// 在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
	ListNode* prev = pos->_prev;
	ListNode* newnode = BuyListNode(x);
	assert(pos);
	newnode->_next = pos;
	pos->_prev = newnode;
	prev->_next = newnode;
	newnode->_prev = prev;
}
// 删除pos位置的节点
void ListErase(ListNode* pos)
{
	ListNode* prev = pos->_prev;
	ListNode* next = pos->_next;
	assert(pos);
	free(pos);
	prev->_next = next;
	next->_prev = prev;
}

void ListRemove(List* plist, LTDataType x)  //移除
{
	ListNode* node = ListFind(plist, x);
	assert(plist);
	if (node != plist->_head)
	{
		ListErase(node);
	}
}

int ListSize(List* plist)  //节点个数
{
	int size = 0;
	ListNode* cur = plist->_head->_next;
	assert(plist);
	while (cur != plist->_head)
	{
		size++;
		cur = cur->_next;
	}
	printf("%d", size);
	return size;

}
int ListEmpty(List* plist) //清空链表
{
	assert(plist);
	printf("%d", plist->_head->_next == plist->_head ? 0 : -1);
	return 0;
}

void ListReverse(List* plist)   //反向链表
{
	ListNode* head = plist->_head;
	ListNode* cur = head->_next;
	ListNode* tmp = NULL;
	assert(plist);
	while (cur != plist->_head)
	{
		tmp = cur->_next;
		cur->_next = cur->_prev;
		cur->_prev = tmp;
		cur = cur->_prev;
	}
	tmp = head->_next;
	head->_next = head->_prev;
	head->_prev = tmp;
}
void ListPrint(List* plist)
{
	ListNode* head = plist->_head;
	ListNode* cur = head->_next;
	assert(plist);
	while (cur != head)
	{
		printf("<-%d->", cur->_data);
		cur = cur->_next;
	}
	printf("\n");
}

这里就是我们所实现的接口代码。上面的尾插,尾删,头插,头删,头可以用 Insert,Erase,替换,来使代码的复量减小,简单实现,就可以使用那样的想法。

下面我们再看看,函数调用的接口

#include"Slist.h"

int main()
{
	List s;
	ListInit(&s);
	ListPushBack(&s, 1);
	ListPushBack(&s, 2);
	ListPushBack(&s, 3);
	ListPushBack(&s, 4);
	ListPushBack(&s, 5);
	ListPushBack(&s, 6);
	ListPushBack(&s, 7);

	ListPrint(&s);
	ListPopBack(&s);
	ListPrint(&s);
	ListPushFront(&s, 0);
	ListPrint(&s);
	ListPopFront(&s);
	ListPrint(&s);

	ListRemove(&s, 3);
	ListPrint(&s);

	ListNode* pos = ListFind(&s, 5);
	ListInsert(pos, 30);
	ListPrint(&s);


	ListErase(pos);
	ListPrint(&s);

	ListReverse(&s);
	ListPrint(&s);
  }

上面的就是我们所实现的双向链表的接口,以及实现代码,下来我们再看看执行结果。

在这里插入图片描述

最后,我还想把链表和顺序表比较一下,

《一》 顺序表:一白遮百丑

白:空间连续、支持随机访问

丑:1.中间或前面部分的插入删除时间复杂度O(N)
2.增容的代价比较大。

《二》 链表:一(胖黑)毁所有

胖黑:以节点为单位存储,不支持随机访问

所有:1.任意位置插入删除时间复杂度为O(1)
2.没有增容问题,插入一个开辟一个空间。

顺序表的实现代码及接口https://blog.csdn.net/dpfxaca6/article/details/86717082
单向链表的实现代码及接口https://blog.csdn.net/dpfxaca6/article/details/89472595

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值