双向链表

前言:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

在这里插入图片描述

由图可知双向链表由头指针尾指针数据域组成。之前的单链表就只有一个指针和一个数据域,这也造成了单链表访问时只能从头开始,直到链表的结尾。而双向链表前后的有两个指针,既可以从头遍历到尾, 又可以从尾遍历到头,也就是一个节点既有向前连接的引用, 也有一个向后连接的引用。因此,双向链表可以有效的解决单向链表中提到的问题。

1.定义节点属性

struct Node
{
	int data;
	struct Node*front;
	struct Node*tail;
};

2.创建一个有头的双向链表

struct Node*createList()
{
	struct Node*headNode = (struct Node*)malloc(sizeof(struct Node));
	headNode->front = headNode;
	headNode->tail = headNode;
	return headNode;
}

3.创建一个节点

struct Node*createNode(int data)
{
	struct Node*newNode = (struct Node*)malloc(sizeof(struct Node));
	newNode->data = data;
	newNode->front = NULL;
	newNode->tail = NULL;
	return newNode;
}

4.插入节点–>头插法
第一次插入时
在这里插入图片描述

void insertByHead(struct Node*list, int data)
{
	struct Node*newNode = createNode(data);
	if (list->tail != NULL)
	{
		//第一次是插入时,list->tail==NULL;
		//所以尾节点指针不需要处理
		newNode->tail = list->tail;
		list->tail->front = newNode;
	}
	newNode->front = list;
	list->tail = newNode;
}

5.指定位置插入
在这里插入图片描述

void inserteByAppion(struct Node*list, int data, int posData)
{
	struct Node*posFrontNode = list;
	struct Node*posNode = list->tail;
	while (posNode != NULL&&posNode->data != posData)
	{
		posFrontNode = posNode;
		posNode = posFrontNode->tail;
	}
	if (posNode == NULL)
	{
		printf("指定位置不存在,无法插入");
		return;
	}
	else
	{
		struct Node*newNode = createNode(data);
		newNode->tail = posNode;
		posNode->front = newNode;
		posFrontNode->tail = newNode;
		newNode->front = posFrontNode;
	}
}

6.表头法删除

void deleteByHead(struct Node*list)
{
	if (list->tail != NULL)
	{
		struct Node*fristNode = list->tail;
		list->tail = fristNode->tail;
		if (fristNode->tail != NULL)
		{
			fristNode->tail->front = list;
		}
		free(fristNode);
	}
}

7.指定位置删除

void deleteAppion(struct Node*list, int posData)
{
	struct Node*posFrontNode = list;
	struct Node*posNode = list->tail;
	while (posNode->data != posData)
	{
		posFrontNode = posNode;
		posNode = posFrontNode->tail;
	}
	if (posNode == NULL)
	{
		printf("抱歉,没有找到指定位置");
		return;
	}
	else
	{
		posFrontNode->tail = posNode->tail;
		if (posNode->tail != NULL)
		{
			posNode->tail->front = posFrontNode;
			free(posNode);
		}
	}
}

8.表尾插入

void inserteByTail(struct Node*list, int data)
{
	struct Node*tailNode = list;
	while (tailNode->tail != NULL)
	{
		tailNode = tailNode->tail;
	}
	struct Node*newNode = createNode(data);
	tailNode->tail = newNode;
	newNode->front = tailNode;
}

9.表尾删除

void deleteByTail(struct Node*list)
{
	struct Node*tailFrontNode = NULL;
	struct Node*tailNode = list;
	while (tailNode->tail != NULL)
	{
		tailFrontNode = tailNode;
		tailNode = tailNode->tail;
	}
	//当链表只有表头时,不能做以下操作
	if (tailFrontNode != NULL)
	{
		tailFrontNode->tail = NULL;
		free(tailNode);
	}
}

10.打印链表

void printList(struct Node*list)
{
	struct Node*pMove = list->tail;
	while (pMove != NULL)
	{
		printf("%d\t", pMove->data);
		pMove = pMove->tail;
	}
	printf("\n");
}

测试代码

int main()
{
	struct Node*list = createList();
	for (int i = 0;i < 10;i++)
	{
		insertByHead(list, i);
	}
	printList(list);
	deleteAppion(list, 4);
	printList(list);
	inserteByAppion(list, 4, 3);
	printList(list);
	inserteByTail(list, 89);
	printList(list);
	for (int i = 0;i < 10;i++)
	{
		deleteByTail(list);
	}
	printList(list);
	system("pause");
	return 0;
}

结果图:
在这里插入图片描述
总结: 双向链表的实现实际上与单链表的做法差不多,仅仅多了一个头节点指针需要处理,在实现头插法是得先判断后节点是否为空(即是否第一次插入),是则需要特殊处理,指定位置插入是,需要注意处理四个节点指针变量。赶紧动手试试吧…

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值