数据结构--双向链表--C语言

单链表的缺陷:

查找速度慢,找不到前驱。

如:单链表的尾删、插入、修改的时间复杂度都是O(N),原因在于:不能直接找到前驱,需要从头开始一个一个找。

缺陷解决方案:双向链表

双向链表

1.双向链表的结构(8种)

单向、双向、带头、不带头、循环、非循环

(带头结点 在头插、尾插、头删、尾删等操作上更加方便)

注意:头结点的值去存链表的长度是错误的,如遇到溢出时就解释不通

(1)无头单向非循环

结构简单,一般不会单独用来存数据,更多是作为子结构,如哈希桶,图的邻接表等。

(2)带头双向循环链表

结构复杂,用来单独存数据。

数据结构--双向链表--C语言

创建双向链表的过程中:每个结点都有两个指针域,一个prior指针指向前一个结点,一个next指针指向后一个结点。

2.双链表的创建

line* initLine(line* head)//创建双链表函数
{
	int i = 0;
	line* list = NULL;
	//创建首元结点,链表的头指针为head
	head = (line*)malloc(sizeof(line));
	//初始换结点
	head->next = NULL;
	head->prior = NULL;
	head->data = 1;

	//声明指向首元结点的指针,方便以后像链表中添加新创建的结点
	list = head;
	for (i = 2; i < 5; i++)
	{
		line* body = (line*)malloc(sizeof(line));
		body->next = NULL;
		body->prior = NULL;
		body->data = i;

		//新节点与链表最后一个节点建立关系
		list->next = body;
		body->prior = list;
		list = list->next;
	}
	//返回新创建的链表
	return head;

}

双向链表的打印/输出:

void display(line* head)//输出链表
{
	line* temp = head;
	while (temp)
	{
		//如果该节点无后继结点
		if (temp->next == NULL)
		{
			printf("%d\n", temp->data);
		}
		else
		{
			printf("%d<->", temp->data);
		}
		temp = temp->next;
	}
}

总的代码:

#include<stdio.h>
#include<stdlib.h>

//声明结构体
typedef struct line{
	struct line* prior;
	int data;
	struct line* next;
}line;

//创建双链表函数
line* intitLine(line* head);
//输出双链表函数
void display(line* head);

line* initLine(line* head)//创建双链表函数
{
	int i = 0;
	line* list = NULL;
	//创建首元结点,链表的头指针为head
	head = (line*)malloc(sizeof(line));
	//初始换结点
	head->next = NULL;
	head->prior = NULL;
	head->data = 1;

	//声明指向首元结点的指针,方便以后像链表中添加新创建的结点
	list = head;
	for (i = 2; i < 5; i++)
	{
		line* body = (line*)malloc(sizeof(line));
		body->next = NULL;
		body->prior = NULL;
		body->data = i;

		//新节点与链表最后一个节点建立关系
		list->next = body;
		body->prior = list;
		list = list->next;
	}
	//返回新创建的链表
	return head;

}

void display(line* head)//输出链表
{
	line* temp = head;
	while (temp)
	{
		//如果该节点无后继结点
		if (temp->next == NULL)
		{
			printf("%d\n", temp->data);
		}
		else
		{
			printf("%d<->", temp->data);
		}
		temp = temp->next;
	}
}


int main()
{
	line* head = NULL;
	head = initLine(head);
	display(head);
	printf("链表中第4个结点的直接前驱是:%d", head->next->next->next->prior->data);
	system("pause");
	return 0;
}

3.双向链表的插入:

(1)表头插入:

数据结构--双向链表--C语言

假设双向链表的表头结点为head,要插入的元素为temp:

第一步:temp->next=head; head->prior=temp;

第二步:将head移动到temp所处的表头位置。

(2)表中插入:

数据结构--双向链表--C语言

(3)表尾插入

数据结构--双向链表--C语言

line* insertLine(line* head, int data, int add)//data为要添加的新数据,add为要添加的链表中的位置
{
	//新建数据为data的结点
	line* temp = (line*)malloc(sizeof(line));
	temp->data = data;
	temp->prior = NULL;
	temp->next = NULL;

	//表头插入时
	if (add ==1)
	{
		temp->next = head;
		head->prior = temp;
		head = temp;
	}
	else
	{
		int i = 0;
		line* body = head;
		//找到插入位置的前一个结点
		for (i = 1; i < add - 1; i++)
		{
			body = body->next;
			if (body == NULL)
			{
				printf("插入位置错误\n");
				break;
			}
		}
		if (body!=NULL)
		{
			if (body->next == NULL)
			{
				body->next = temp;
				temp->prior = body;
				temp->next = NULL;
			}
			else
			{
				body->next->prior = temp;
				temp->next = body->next;
				body->next = temp;
				temp->prior = body;
			}
		}
	}
	return head;

}

4.删除双向链表:

数据结构--双向链表--C语言

line* delLine(line* head, int data)//删除结点,data为删除的数据值
{
	line* temp = head;
	//先遍历链表
	while (temp)
	{
		//判断当前结点数据域和data是否相等,若相等,则摘除该节点
		if (temp->data == data)
		{
			temp->prior->next = temp->next;
			temp->next->prior = temp->prior;
			free(temp);
			return head;
		}
		temp = temp->next;
	}
	printf("链表中无该数据元素\n");
	return head;
}

5.更新节点

line* updateLine(line* p, int add, int update)//更新节点数据值,add为节点位置
{
	int i = 0;
	line* temp = p;
	//遍历到被删除的结点
	for (i = 1; i < add; i++)
	{
		temp = temp->next;
		if (temp == NULL)
		{
			printf("更改位置有误!\n");
			break;
		}
	}
	if (temp != NULL)
	{
		temp->data = update;
	}
	return p;
}

全部代码:

#include<stdio.h>
#include<stdlib.h>

//声明结构体
typedef struct line{
	struct line* prior;
	int data;
	struct line* next;
}line;

//创建双链表函数
line* intitLine(line* head);
//输出双链表函数
void display(line* head);
//向双向链表中插入新元素
line* insertLine(line* head, int data, int add);
//删除链表结点
line* delLine(line* head, int data);
//双向链表更新节点
line* updateLine(line* p, int add, int update);


line* initLine(line* head)//创建双链表函数
{
	int i = 0;
	line* list = NULL;
	//创建首元结点,链表的头指针为head
	head = (line*)malloc(sizeof(line));
	//初始换结点
	head->next = NULL;
	head->prior = NULL;
	head->data = 1;

	//声明指向首元结点的指针,方便以后像链表中添加新创建的结点
	list = head;
	for (i = 2; i < 5; i++)
	{
		line* body = (line*)malloc(sizeof(line));
		body->next = NULL;
		body->prior = NULL;
		body->data = i;

		//新节点与链表最后一个节点建立关系
		list->next = body;
		body->prior = list;
		list = list->next;
	}
	//返回新创建的链表
	return head;

}

void display(line* head)//输出链表
{
	line* temp = head;
	while (temp)
	{
		//如果该节点无后继结点
		if (temp->next == NULL)
		{
			printf("%d\n", temp->data);
		}
		else
		{
			printf("%d<->", temp->data);
		}
		temp = temp->next;
	}
}

line* insertLine(line* head, int data, int add)//data为要添加的新数据,add为要添加的链表中的位置
{
	//新建数据为data的结点
	line* temp = (line*)malloc(sizeof(line));
	temp->data = data;
	temp->prior = NULL;
	temp->next = NULL;

	//表头插入时
	if (add ==1)
	{
		temp->next = head;
		head->prior = temp;
		head = temp;
	}
	else
	{
		int i = 0;
		line* body = head;
		//找到插入位置的前一个结点
		for (i = 1; i < add - 1; i++)
		{
			body = body->next;
			if (body == NULL)
			{
				printf("插入位置错误\n");
				break;
			}
		}
		if (body!=NULL)
		{
			if (body->next == NULL)
			{
				body->next = temp;
				temp->prior = body;
				temp->next = NULL;
			}
			else
			{
				body->next->prior = temp;
				temp->next = body->next;
				body->next = temp;
				temp->prior = body;
			}
		}
	}
	return head;

}


line* delLine(line* head, int data)//删除结点,data为删除的数据值
{
	line* temp = head;
	//先遍历链表
	while (temp)
	{
		//判断当前结点数据域和data是否相等,若相等,则摘除该节点
		if (temp->data == data)
		{
			temp->prior->next = temp->next;
			temp->next->prior = temp->prior;
			free(temp);
			return head;
		}
		temp = temp->next;
	}
	printf("链表中无该数据元素\n");
	return head;
}


line* updateLine(line* p, int add, int update)//更新节点数据值,add为节点位置
{
	int i = 0;
	line* temp = p;
	//遍历到被删除的结点
	for (i = 1; i < add; i++)
	{
		temp = temp->next;
		if (temp == NULL)
		{
			printf("更改位置有误!\n");
			break;
		}
	}
	if (temp != NULL)
	{
		temp->data = update;
	}
	return p;
}



int main()
{
	line* head = NULL;
	head = initLine(head);
	display(head);
	printf("链表中第4个结点的直接前驱是:%d\n", head->next->next->next->prior->data);
	printf("在第三个位置插入7:\n");
	head = insertLine(head, 7, 3);
	display(head);
	printf("删除7\n");
	head = delLine(head, 7);
	display(head);
	printf("修改第三个位置的树为4:\n");
	head = updateLine(head, 3, 4);
	display(head);
	system("pause");
	return 0;
}

运行结果:

数据结构--双向链表--C语言

 今天的状态好多了,加油!!!参考了这位大大的一些代码和思想:双向链表基本操作(C语言实现)详解 (biancheng.net)

 

 

上一篇:全站最硬核 百万字强肝RocketMq源码 火热更新中~(九十五)延时队列


下一篇:zip文件自动打包