数据结构:单链表、双链表的区别与实现

目录

 

一、链表

二、单向链表与双向链表的区别

三、单链表的实现

四、双向(循环)链表的实现


一、链表

链表所需要的功能:

  • 初始化
  • 创建新节点
  • 插入
  • 删除
  • 查询
  • 链表的销毁(释放包括头结点在内的空间)
  • 链表的清空(释放除了头结点以外的空间)

链表的优缺点:

  • 优点:链表不需要初始化容量,可以任意加减元素,并且添加与删除元素十分快捷,只需要改变指针域指向的内容即可内存利用率高,
  • 缺点:查找元素,需要通过遍历链表来查找,十分耗时
  • 适用于:需要频繁添加或者删除操作的场景

二、单向链表与双向链表的区别

单向链表与双向(循环)链表的区别:

  • 在存储空间方面:单链表需要的存储空间比双向链表的要少,因为双向链表不仅保存有指向下一个节点的指针,还保存有指向上一个节点的指针,需要较大的空间来存储双向链表的指针域。
  • 在处理时间方面:双向链表的插入与删除操作比单链表的时间要快很多。在最末尾插入的时候,单链表需要找到需要插入位置的前一个节点,需要遍历整个链表,时间复杂度为O(n),而双向链表只需要head->tail,就可以得到最后一个节点的位置,然后就可以进行插入操作,时间复杂度为O(1)。在删除操作方面,单链表需要遍历到需要删除的节点的前一个节点,双向链表需要遍历到需要删除的节点,时间复杂度同为O(n)。

一个提高单链表尾部插入效率的小方法:

  • 定义一个指针tail,专门指向单链表的最末尾。如图所示

三、单链表的实现

注意:在处理单链表的插入的时候,优先处理新节点!

  • 链表的定义
/*结构体*/
typedef int datatype;
typedef struct node
{
	datatype data;
	struct node *next;

}node,*list;

/*单链表的尾指针*/
struct node *tail;
  • 链表的初始化
/*
	创建头节点
 */
list initNode()
{
	list head = malloc(sizeof(node));
	if(head != NULL)
	{
		head->next = NULL;
	}

	tail = head;//尾指针指向头结点

	return head;
}
  • 创建新的节点
/*
	创建新节点
 */
list newNode(datatype n)
{
	list new = malloc(sizeof(node));
	if(new != NULL)
	{
		new->data = n;
		new->next = NULL;
	}

	return new;
}
  • 尾插法:插入节点
/*
	尾插法,添加节点(包含尾指针)
	插入需要注意:优先处理新节点、不先动旧的链表
 */
bool insertNode_tail(list new)
{
	/*判断新的节点是否为空*/
	if (new == NULL)
	{
		printf("new point to NULL\n");
		return false;
	}

	new->next = NULL;
	tail->next = new;
	tail = new;//tail指向最后一个节点

	return true;
}

/*
    不含有尾指针
 */
bool insertNode_tail(list new,list head)
{
	/*判断新的节点是否为空*/
	if (new == NULL)
	{
		printf("new point to NULL\n");
		return false;
	}

    list p = head;
	while(p->next != NULL)//搜索到最后的节点
	{
		p = p->next;
	}

    new->next = NULL;//优先处理新节点
    p->next = new;    

	return true;
}
  • 删除节点
/*
	删除节点:输入对应数字的负数形式,则会删除对应数字
 */
bool delNode(datatype data, list head)
{
	//数据处理
	data = -data;

	list p = head;
	while(p->next != NULL)//找到要删除的节点的前一个节点
	{
		if(p->next->data == data)break;
		p = p->next;
	}

	list del_p = p->next;//要删除的节点
	p->next = del_p->next;
	free(del_p);//释放空间

	tail = head;//将tail指针指向最末尾
	while(tail->next != NULL)
	{
		tail = tail->next;
	}

	return true;
}
  • 查询链表
/*
	查询节点
 */
void showNode(list head)
{
	list p = head->next;
	do
	{
		printf("%d\t", p->data);
		p = p->next;
	}while(p != NULL);

	printf("\n");
}
  • 销毁与清空链表
  • 销毁链表:释放包括头节点的所有空间
  • 清空链表:释放除了头节点的其他节点空间
/*
	销毁整个链表
 */
void destoryAllNode(list head)
{
	list p = head;
	list next_p = NULL;
	while(p != NULL)
	{
		next_p = p->next;//存储下一个节点指针
		free(p);//释放当前节点
		p = next_p;//指向销毁后的下一个节点
	}
}

/*
	清空链表
 */
void clearNode(list head)
{
	list p = head->next;//p指向第一个节点
	list next_p = NULL;
	while(p != NULL)
	{
		next_p = p->next;
		free(p);
		p = next_p;
	}
}

四、双向(循环)链表的实现

  • 双向链表的定义
/*结构体*/
typedef int datatype;
typedef struct node
{
	datatype data;
	struct node *next, *pre;

}node,*list;
  • 双向链表的初始化
/*
	创建头节点
 */
list initNode()
{
	list head = malloc(sizeof(node));
	if(head != NULL)
	{
		head->next = head;
		head->pre = head;
	}

	return head;
}
  • 创建新节点
/*
	创建新节点
 */
list newNode(datatype n)
{
	list new = malloc(sizeof(node));
	if(new != NULL)
	{
		new->data = n;
		new->next = NULL;
		new->pre = NULL;
	}

	return new;
}
  • 尾插法:插入节点
/*
	尾插法,添加节点
	插入需要注意:优先处理新节点、不先动旧的链表
 */
bool insertNode_weicha(list new, list head)
{
	/*判断新的节点是否为空*/
	if (new == NULL)
	{
		printf("new point to NULL\n");
		return false;
	}

	//优先处理新的节点
	new->pre = head->pre;//head->pre 为最后一个节点
	new->next = head;
	head->pre->next = new;//倒数第二个节点指向新的节点
	head->pre = new;//此时new为最后一个	

	return true;
}
  • 删除节点
/*
	删除节点:输入对应数字的负数形式,则会删除对应数字
 */
bool delNode(datatype data, list head)
{
	//数据处理
	data = -data;

	list p = head->next;//p为第一个节点
	while(p->next != head)
	{
		if(p->data == data)break;//p指向要删除的节点
		p = p->next;
	}

	p->next->pre = p->pre;
	p->pre->next = p->next;
	p->pre = NULL;
	p->next = NULL;

	free(p);//释放空间
	return true;
}
  • 查询节点
/*
	查询节点
 */
void showNode(list head)
{
	list p = head->next;//p指向第一个节点
	do
	{
		printf("%d\t", p->data);
		p = p->next;
	}while(p != head);

	printf("\n");
}
  • 销毁与清空链表
/*
	销毁整个链表
 */
void destoryAllNode(list head)
{
	list p = head->next;
	list next_p = NULL;
	while(p != head)
	{
		next_p = p->next;//存储下一个节点指针
		free(p);//释放当前节点
		p = next_p;//指向销毁后的下一个节点
	}

	free(head);
}

/*
	清空链表
 */
void clearNode(list head)
{
	list p = head->next;
	list next_p = NULL;
	while(p != head)
	{
		next_p = p->next;//存储下一个节点指针
		free(p);
		p = next_p;
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鱼的猫丿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值