2.双向链表的实现
2.1定义一个结点
typedef struct line{
int data; //data
struct line *pre; //pre node
struct line *next; //next node
}line,*a;
//分别表示该结点的前驱(pre),后继(next),以及当前数据(data)
- DATA表示数据,其可以是简单的类型(如int,double等等),也可以是复杂的结构体(struct类型);
- pre代表的是前驱指针,它永远指向当前结点的前一个结点,注意,如果当前结点是头结点,则pre指针为空;
- next代表的是后继指针,它永远指向当前结点的下一个结点,注意,如果当前结点是尾结点,则next指针为空。
2.2创建双链表
//创建双链表
line* initLine(line * head){
int number,pos=1,input_data;
//三个变量分别代表结点数量,当前位置,输入的数据
printf("请输入创建结点的大小\n");
scanf("%d",&number);
if(number<1){return NULL;} //输入非法直接结束
//////头结点创建///////
head=(line*)malloc(sizeof(line));
head->pre=NULL;
head->next=NULL;
printf("输入第%d个数据\n",pos++);
scanf("%d",&input_data);
head->data=input_data; //首结点也要储存数据。
line * list=head;
while (pos<=number) {
line * body=(line*)malloc(sizeof(line));
body->pre=NULL;
body->next=NULL;
printf("输入第%d个数据\n",pos++);
scanf("%d",&input_data);
body->data=input_data;
list->next=body;
body->pre=list;
list=list->next;
}
return head;
}
//number用来表示创建的双链表的节点的数量,pos用于配合print语句输出当前数据位置,input_data是后面要输入的数据。
//双链表的一个特殊之处在于首结点也要储存数据。由此结点基本被分成两部分——首结点head和其他结点body。代码很容易看出来,先处理head,再去处理body。list指针指向head,相当于指向第一个结点,就是个工具结点,代替head,省的影响head,你要是用head遍历,到最后返回值head就不对劲了。
//body结点:先初始化好一个节点,填入数据,和前面的结点互指(本结点的pre指向上一个结点,上一个节点的next指向本结点),让list指针指向下一个结点。
2.3插入新结点
//插入数据
line * insertLine(line * head,int data,int add){
//三个参数分别为:进行此操作的双链表,插入的数据,插入的位置
//新建数据域为data的结点
line * temp=(line*)malloc(sizeof(line));
temp->data=data;
temp->pre=NULL;
temp->next=NULL;
//插入到链表头,要特殊考虑
if (add==1) {
temp->next=head;
head->pre=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->pre=body;
}else{
body->next->pre=temp;//意思是下一个结点的pre,这样写比较省事。
temp->next=body->next;
body->next=temp;
temp->pre=body;
}
}
return head;
}
//思路还和单链表差不多,先找到插入位置的前一个结点。
//双链表插入分成三种情况——插入首结点、插入中间结点、插入尾结点。
//插入首结点:和原首结点互指,然后将链表表头地址改为这个新插入的结点的地址。
//插入中间结点:后一个结点指向新结点,新结点指向后一个结点(用前一个结点的next给新结点就行了),完成了后一个结点和新结点互指后,再让前一个结点和新结点互指。
//插入尾结点:直接让新结点和原尾结点互指就完事了,新结点的next在初始化时就已经是NULL了。
2.4删除结点
//删除元素
line * deleteLine(line * head,int data){
//输入的参数分别为进行此操作的双链表,需要删除的数据
line * list=head;
//遍历链表
while (list) {
//判断是否与此元素相等
//删除该点方法为将该结点前一结点的next指向该节点后一结点
//同时将该结点的后一结点的pre指向该节点的前一结点
if (list->data==data) {
list->pre->next=list->next;
list->next->pre=list->pre; //关键的两步,比较省事的写法。
free(list);
printf("--删除成功--\n");
return head;
}
list=list->next;
}
printf("Error:没有找到该元素,没有产生删除\n");
return head;
}
//简单来说就是,让目标删除结点的前一个结点的next直接指向其后的结点,其后的结点再指向目标删除节点前面的结点。
2.5遍历双链表
//遍历双链表,同时打印元素数据
void printLine(line *head){
line *list = head;
int pos=1;
while(list){
printf("第%d个数据是:%d\n",pos++,list->data);
list=list->next;
}
}
//和单链表没啥不一样。
2.6完整的双链表代码
#include<stdio.h>
#include<stdlib.h>
typedef struct line{
int data; //data
struct line *pre; //pre node
struct line *next; //next node
}line;
//分别表示该结点的前驱(pre),后继(next),以及当前数据(data)
//遍历双链表,同时打印元素数据
void printLine(line *head){
line *list = head;
int pos=1;
while(list){
printf("第%d个数据是:%d\n",pos++,list->data);
list=list->next;
}
}
//创建双链表
line* initLine(line * head){
int number,pos=1,input_data;
printf("请输入创建结点的大小\n");
scanf("%d",&number);
if(number<1){return NULL;} //输入非法直接结束
//////头结点创建///////
head=(line*)malloc(sizeof(line));
head->pre=NULL;
head->next=NULL;
printf("输入第%d个数据\n",pos++);
scanf("%d",&input_data);
head->data=input_data;
line * list=head;
while (pos<=number) {
line * body=(line*)malloc(sizeof(line));
body->pre=NULL;
body->next=NULL;
printf("输入第%d个数据\n",pos++);
scanf("%d",&input_data);
body->data=input_data;
list->next=body;
body->pre=list;
list=list->next;
}
return head;
}
//插入数据
line * insertLine(line * head,int data,int add){
//三个参数分别为:进行此操作的双链表,插入的数据,插入的位置
//新建数据域为data的结点
line * temp=(line*)malloc(sizeof(line));
temp->data=data;
temp->pre=NULL;
temp->next=NULL;
//插入到链表头,要特殊考虑
if (add==1) {
temp->next=head;
head->pre=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->pre=body;
}else{
body->next->pre=temp;
temp->next=body->next;
body->next=temp;
temp->pre=body;
}
}
return head;
}
//删除元素
line * deleteLine(line * head,int data){
//输入的参数分别为进行此操作的双链表,需要删除的数据
line * list=head;
//遍历链表
while (list) {
//判断是否与此元素相等
//删除该点方法为将该结点前一结点的next指向该节点后一结点
//同时将该结点的后一结点的pre指向该节点的前一结点
if (list->data==data) {
list->pre->next=list->next;
list->next->pre=list->pre;
free(list);
printf("--删除成功--\n");
return head;
}
list=list->next;
}
printf("Error:没有找到该元素,没有产生删除\n");
return head;
}
int main(){
line *head=NULL;
printf("创建双链表操作\n");
head=initLine(head);
printLine(head);
//////////create line////////////
printf("插入操作\n");
head=insertLine(head,40,2); //为了简化直接写参数了
printLine(head);
//////////insert Line////////////
printf("删除操作\n");
head=deleteLine(head,2); //为了简化直接写参数了
printLine(head);
//////////delete Line////////////
return 0;
}