单链表的缺陷:
查找速度慢,找不到前驱。
如:单链表的尾删、插入、修改的时间复杂度都是O(N),原因在于:不能直接找到前驱,需要从头开始一个一个找。
缺陷解决方案:双向链表
双向链表
1.双向链表的结构(8种)
单向、双向、带头、不带头、循环、非循环
(带头结点 在头插、尾插、头删、尾删等操作上更加方便)
注意:头结点的值去存链表的长度是错误的,如遇到溢出时就解释不通
(1)无头单向非循环
结构简单,一般不会单独用来存数据,更多是作为子结构,如哈希桶,图的邻接表等。
(2)带头双向循环链表
结构复杂,用来单独存数据。
创建双向链表的过程中:每个结点都有两个指针域,一个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)表头插入:
假设双向链表的表头结点为head,要插入的元素为temp:
第一步:temp->next=head; head->prior=temp;
第二步:将head移动到temp所处的表头位置。
(2)表中插入:
(3)表尾插入
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.删除双向链表:
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语言实现)详解 (biancheng.net)