双向链表
双向链表也即有两个指针的链表,分别指向前一个结点和后一个结点
当然此处的双向是指各节点之间的逻辑关系是双向的,但通常头指针只设置一个,除非实际情况需要。
双向链表中各节点包含以下3部分信息:
- 指针域:用于指向当前节点的直接前驱结点
- 数据域:用于存储数据元素
- 指针域:用于指向当前节点的直接后继节点
双向链表的创建
#include<stdio.h>
#include<stdlib.h>
typedef struct line{
struct line * prior;
int data;
struct line * next;
};
line* initLine(line * head){
head = (line*)malloc(sizeof(line));
head -> prior = NULL;
head -> next = NULL;
head -> data = 1;
line * list = head;
for(int i = 2;i <= 5;i++){
line * body = (line*)malloc(sizeof(line));
body ->prior = NULL;
body ->next = 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("链表中的第四个节点的直接前趋是:%d",head -> next -> next -> next-> prior -> data);
return 0;
}
双向链表的基本操作
双向链表中添加元素
分为三种情况:添加在表头、添加在表中、添加在表最后
不同与之前学的几种表,这里双向链表三种情况必须分开讨论
- 当添加元素在表头时,原来的第一个元素的前驱指向添加元素,添加元素的前驱指向NULL,后驱指向原来的第一个元素,并且头指针要从指向原来的第一个元素改成指向添加的元素
- 当添加元素在表的中间位置时,同单链表添加数据,需要新节点先与其直接后继节点建立双层逻辑关系,然后新节点的直接前驱节点与之建立双层逻辑关系
- 当添加元素到表尾,需先找到双链表中最后一个节点,让新节点与最后一个节点进行双层逻辑关系
line* addLine(line * head,int data,int add){
line * temp = head;//新建数据域为num的节点
temp -> data = data;
temp -> prior = NULL;
temp -> next = NULL;
//插入到链表头的情况
if(add == 1){
temp -> next = head;
head -> prior = temp;
head = temp;
}else{//插入到表中的情况
line * body = head;
//找到要插入位置的前一个结点
for(int i = 1;i < add-1;i++){
body = body -> next;
}
if(body->next == NULL){//是最后一个节点
body -> next = temp;
temp -> prior = body;
}else{//并不是最后一个节点
body -> next ->prior = temp;
temp -> next = body -> next;
body -> next = temp;
temp -> prior = body;
}
}
return head;
}
需要注意的是,这里已经改变了head所指向的空间,所以在主函数中调用时,需要用head=addLine()接收一下,否则如果添加元素在表头时,会读取不到添加的元素
双向链表删除节点
删除节点时,先遍历链表,找到要删除的节点,然后将该节点从表中摘除即可
line * delLine(line * head,int del){
line * temp = head;
if(del == 1){
head = head -> next;
head -> prior = NULL;
free(temp);
}
else{
for(int i = 1;i <del; i++){
temp = temp -> next;
if(temp -> next == NULL){
printf("已经循环到最后一个数了,后面已经没有数据了\n");
temp -> prior -> next = NULL;
free(temp);
return head;
}
}
temp -> prior -> next = temp -> next;
temp -> next -> prior = temp -> prior;
free(temp);
}
return head;
}
双向表查找元素
通过遍历链表,找到想要找到的元素的位置
int searchLine(line * head , int data){
line * temp = head;
int num=1;
while(data == temp -> data){
temp = temp -> next;
num ++;
}
return num;
}
双向表修改元素
通过遍历链表,找到想要修改的元素,再替换他的值
line * changeLine(line * head , int data , int num){
line * temp = head;
for(int i = 1; i<num;i++){
temp = temp -> next;
}
temp -> data = data;
return head;
}