头文件:
#ifndef __LINK_h
#define __LINK_h
#include<stdio.h>
#include<stdlib.h>
typedef struct link{
int data;
struct link *next;
struct link *prev;
}link_t, *plink_t;
plink_t create_node(int d);
void insert_tail(plink_t p, plink_t node);
void del_node(plink_t node);
void update(plink_t old, plink_t new);
//操作
//==============================
//函数
plink_t link_init();
void link_insert_head(plink_t p, int d);
void display(plink_t p);
void link_insert_tail(plink_t p, int d);
void link_del(plink_t p, int d);
void link_update(plink_t head, int old, int new);
#endif
主函数代码:
#include "link.h"
int main(void){
plink_t head;
head = link_init();
printf("头节点初始化完成\n");
//输入数据,并根据数据形成节点,头插和尾插
//temp只是为了跳出循环
int temp, data;
while(1){
temp = scanf("%d", &data);
if(temp == 0){
break;
}
//头插法
link_insert_head(head, data);
display(head);
}
getchar();
printf("开始尾插操作\n");
while(1){
temp = scanf("%d", &data);
if(temp == 0){
break;
}
//尾插法
link_insert_tail(head, data);
display(head);
}
getchar();
printf("开始删除操作\n");
while(1){
temp = scanf("%d", &data);
if(temp == 0){
break;
}
link_del(head, data);
display(head);
}
getchar();
printf("开始替换操作\n");
int new;
while(1){
printf("输入被替换的旧数据:");
temp = scanf("%d", &data);
if(temp == 0){
break;
}
printf("输入替换的新数据");
temp = scanf("%d", &new);
if(temp == 0){
break;
}
link_update(head, data, new);
display(head);
}
return 0;
}
函数代码:
#include "link.h"
//初始化操作
plink_t create_node(int d){
plink_t node = (plink_t)malloc(sizeof(link_t));
if(NULL == node){
perror("malloc");
return NULL;
}
node->data = d;
node->next = node;
node->prev = node;
return node;
}
//插入操作
void insert_tail(plink_t p, plink_t node){
node->next = p->next;
node->prev = p;
p->next->prev = node;
p->next = node;
}
//删除操作
void del_node(plink_t node){
node->prev->next=node->next;
node->next->prev=node->prev;
node->prev=node;
node->next=node;
free(node);
}
//替换操作
void update(plink_t old, plink_t new){
new->next = old->next;
new->prev = old->prev;
new->prev->next = new;
new->next->prev = new;
free(old);
}
//=====================================
//初始化函数
plink_t link_init(){
return create_node(-1);
}
//头插函数
void link_insert_head(plink_t p, int d){
plink_t node = create_node(d);
if(NULL == node){
return;
}
insert_tail(p, node);
return;
}
//尾插函数
void link_insert_tail(plink_t p, int d){
plink_t node = create_node(d);
if(NULL == node){
return;
}
insert_tail(p->prev, node);
//return;
}
//删除函数
void link_del(plink_t p, int d){
plink_t head = p;
while(p->next != head){
p = p->next;
if(p->data == d){
del_node(p);
return;
}
}
printf("没有找到");
}
//替换函数
void link_update(plink_t p, int old, int new){
plink_t head = p;
while(p->next != head){
p = p->next;
if(p->data == old){
plink_t new_node = create_node(new);
if(NULL == new_node){
return;
}
update(p, new_node);
return;
}
}
}
//遍历函数
void display(plink_t p){
plink_t head = p;
while(p->next != head){
p = p->next;
printf ("%d ", p->data);
}
printf("\n");
}
段错误的出现:
在替换函数中,若是没有最后一个return,则会继续执行while循环,但是update函数会将p指向了一个无效地址,也就是free(p)操作,所以会报段错误
但如果注释掉free(p)这一步,那么它就不会报段错误,因为它还有指向前趋结点和指向后继节点的关系,还是能找到p的地址,也就会继续运行while循环
注意的是,这时候的替换操作会全部替换掉后续所有一样的数字,比如1 2 3 3 2 1,将3替换成4,它会全部替换,即1 2 4 4 2 1
此时,想替换单个数字,则需要加上return跳出循环。
插入操作和替换操作:
先将新的结点指向原本链表中的两个相连结点,再断开原本相连的两个结点,将它们指向新结点
需要注意的是!3、4不能和1、2调换位置,如果先执行 p->next = node后再执行 node->next = p->next就会失败,因为p->next指向的结点已经发生改变,原本链表中的成员关系已经发生了改变
思考:按理说,1和2能够互换,3和4能够互换,12和34之间不能互换,但是3能和12互换。因为没影响到后面的指针域改变,但为了减少错误的出现概率,还是按照以下方式编写
node->next = p->next;
node->prev = p;
p->next->prev = node;
p->next = node;