赞
踩
前面介绍了单链表,由于单链表遍历查找是单向性的,故引出了双向链表的概念,也叫双链表,既可以向前查找,也可以向后遍历。
在单链表的基础上增加一个前驱指针,每个数据结点中都有两个指针,分别指向直接后继和直接前驱。初始化一个头节点,前驱指针和后驱指针均指向NULL,头节点的数据域是有数据的,这点跟单链表不同。
pre表示前驱指针,指向当前结点的前一个结点,如果当前结点是头结点,则pre指针为空;
next表示后继指针,指向当前结点的下一个结点,如果当前结点是尾结点,则next指针为空。
- typedef struct _NODE {
- int data;
- struct _NODE *next; //后继指针
- struct _NODE *pre; //前驱指针
- }Node,*Nodelist;
调用malloc函数申请内存的时候返回值是指向申请的地址,如果申请失败返回NULL,这里我们最好要养成习惯判断是否内存申请成功;exit函数的作用是退出当前程序的进程;头节点的两个指针都指向NULL,并给头节点输入数据;当输入文件结束符(window下输入ctrl+z、linux下输入ctrl+d)的时候就完成链表的创建。
- Nodelist double_link_create()
- {
- int Data = 0;
- Node *p = NULL;
- Node *head = (Nodelist)malloc(sizeof(Node));
- if(head == NULL){
- printf("head malloc fail.\n");
- exit(-1);
- }
- head->pre = NULL;
- head->next = NULL;
- printf("window下输入ctrl+z完成创建;linux下输入ctrl+d完成创建\n");
- printf("please input data:");
- scanf("%d",&Data);
- head->data = Data;
- p = head;
-
- while(scanf("%d",&Data) != EOF){
- Node *q = (Nodelist)malloc(sizeof(Node));
- if(q == NULL){
- printf("malloc fail.\n");
- exit(-1);
- }
- q->data = Data;
- q->pre = p;
- q->next = NULL;
- p->next = q;
- p = q;
- }
-
- return head;
- }
双向链表的插入操作,首先需要开辟一个新的节点内存空间,然后将它的pre指针指向所需插入位置的前一个结点,同时,它所需插入的前一个结点的next指针修改指向为该新的结点,同理,该新的结点的next指针将会指向一个原本的下一个结点,而修改下一个结点的pre指针为指向新结点自身。
还需要对插入位置进行考虑:①插入到头节点位置处理;②插入到链表中间处理;③插入到表尾处理;④插入位置超过链表本身长度处理。
- Nodelist double_link_insert(Nodelist h, int addr, int data)
- {
- Node *p = h;
- Node *add_node = (Nodelist)malloc(sizeof(Node));
- if(add_node == NULL){
- printf("malloc fail.\n");
- exit(-1);
- }
- add_node->data = data;
-
- if(addr == 1){ //插入到头节点要特殊考虑
- add_node->pre = NULL;
- add_node->next = p;
- p->pre = add_node;
- h = add_node; //头节点指向新节点
- return h;
- }
- else{
- for(int i = 1; i < addr; i++){
- if(p->next != NULL){
- p = p->next;
- }
- else{ //addr错误则将新节点链接在表尾
- printf("addr is too large\n");
- add_node->pre = p;
- add_node->next = NULL;
- p->next = add_node;
- return h;
- }
- }
- add_node->pre = p->pre;
- add_node->next = p;
- p->pre = add_node;
- }
- return h;
- }
首先,指定需要删除的结点位置,选中这个结点的前一个结点,将前一个结点的next指针指向自己的下一个结点,同时,选中该节点的下一个结点,将下一个结点的pre指针修改指向为自己的上一个结点,最后,释放删除结点的内存空间。
逻辑注意事项:①假设指定删除位置超过链表本身长度如何处理;②删除头节点处理;③删除为节点处理;④删除中间节点处理。
- Nodelist double_link_delete(Nodelist h, int addr)
- {
- Node *p = h;
- for(int i = 1; i < addr; i++){
- if(p->next != NULL){
- p = p->next;
- }
- else{
- printf("addr error,function exit.\n");
- return h;
- }
- }
- if(addr == 1){ //删除头节点
- p->next->pre = NULL;
- h = p->next;
- free(p);
- }
- else{
- if(p->next == NULL){ //删除尾节点
- p->pre->next = NULL;
- free(p);
- }
- else{
- p->pre->next = p->next;
- p->next->pre = p->pre;
- free(p);
- }
- }
- return h;
- }
双链表主要懂如何插入、删除操作,其它的修改、查询、打印等都跟单链表差不多,逻辑点比较简单,重点是学会对指针的使用。
- /****************************************
- Fuction:C语言实现双向链表
- Time:9/21/2022
- Author:Qurry
- ****************************************/
-
-
- #include <stdio.h>
- #include <stdlib.h>
-
- typedef struct _NODE {
- int data;
- struct _NODE *next; //后继指针
- struct _NODE *pre; //前驱指针
- }Node,*Nodelist;
-
- /********** 创建双链表 ************/
- Nodelist double_link_create()
- {
- int Data = 0;
- Node *p = NULL;
- Node *head = (Nodelist)malloc(sizeof(Node));
- if(head == NULL){
- printf("head malloc fail.\n");
- exit(-1);
- }
- head->pre = NULL;
- head->next = NULL;
- printf("window下输入ctrl+z完成创建;linux下输入ctrl+d完成创建\n");
- printf("please input data:");
- scanf("%d",&Data);
- head->data = Data;
- p = head;
-
- while(scanf("%d",&Data) != EOF){
- Node *q = (Nodelist)malloc(sizeof(Node));
- if(q == NULL){
- printf("malloc fail.\n");
- exit(-1);
- }
- q->data = Data;
- q->pre = p;
- q->next = NULL;
- p->next = q;
- p = q;
- }
-
- return head;
- }
-
- /********* 链表增加节点 ***********
- * addr:增加节点的位置
- * data:增加节点的数据
- * ********************************/
- Nodelist double_link_insert(Nodelist h, int addr, int data)
- {
- Node *p = h;
- Node *add_node = (Nodelist)malloc(sizeof(Node));
- if(add_node == NULL){
- printf("malloc fail.\n");
- exit(-1);
- }
- add_node->data = data;
-
- if(addr == 1){ //插入到头节点要特殊考虑
- add_node->pre = NULL;
- add_node->next = p;
- p->pre = add_node;
- h = add_node; //头节点指向新节点
- return h;
- }
- else{
- for(int i = 1; i < addr; i++){
- if(p->next != NULL){
- p = p->next;
- }
- else{ //addr错误则将新节点链接在表尾
- printf("addr is too large\n");
- add_node->pre = p;
- add_node->next = NULL;
- p->next = add_node;
- return h;
- }
- }
- add_node->pre = p->pre;
- add_node->next = p;
- p->pre = add_node;
- }
- return h;
- }
-
- /*********** 链表删除节点 *************
- * addr:删除节点的位置
- * **************************************/
- Nodelist double_link_delete(Nodelist h, int addr)
- {
- Node *p = h;
- for(int i = 1; i < addr; i++){
- if(p->next != NULL){
- p = p->next;
- }
- else{
- printf("addr error,function exit.\n");
- return h;
- }
- }
- if(addr == 1){ //删除头节点
- p->next->pre = NULL;
- h = p->next;
- free(p);
- }
- else{
- if(p->next == NULL){ //删除尾节点
- p->pre->next = NULL;
- free(p);
- }
- else{
- p->pre->next = p->next;
- p->next->pre = p->pre;
- free(p);
- }
- }
- return h;
- }
-
- /********** 链表修改数据 **********
- * old_data:要修改的数据
- * new_data:修改后的数据
- * ****************************************/
- void double_link_modify(Nodelist h, int old_data, int new_data)
- {
- Node *p = h;
- while(p->data != old_data){
- if(p->next != NULL){
- p = p->next;
- }
- else{
- printf("old_data error!\n");
- return;
- }
- }
- p->data = new_data;
- }
-
- /******** 链表查找数据 *********
- * addr:查找数据的位置
- * *********************************/
- void double_link_find(Nodelist h, int addr)
- {
- Node *p = h;
- for(int i = 1; i < addr; i++){
- if(p->next != NULL){
- p = p->next;
- }
- else{
- printf("addr error,function exit.\n");
- return;
- }
- }
- printf("Data:%d\n",p->data);
- }
-
- /********** 链表数据打印 **********/
- void double_link_print(Nodelist h)
- {
- Node *p = h;
- int inode = 1;
- while(1){
- printf("Node[%d]:%d\n",inode++,p->data);
- if(p->next == NULL){
- return;
- }
- else{
- p = p->next;
- }
- }
- }
-
- /*********** 选择菜单 **************/
- int menu_select()
- {
- int num;
- printf("1:插入节点 2:修改节点 3:删除节点 4:打印节点数据 5:查找节点数据 0:退出\n");
- printf("Please input num : ");
- scanf("%d",&num);
- return num;
- }
-
- /************ 退出释放内存 ************/
- void free_node(Nodelist H)
- {
- Node *P = H->next;
- while(1){
- free(P);
- P = P->next;
- if(P->next == NULL){
- free(P);
- break;
- }
- }
- }
-
- void main()
- {
- Node *head = NULL;
- int mode,addr,data1,data2;
- head = double_link_create();
-
- while(1){
- mode = menu_select();
- switch (mode)
- {
- case 0:
- printf("Bye bye!\n");
- free_node(head);
- exit(0);
-
- case 1:
- printf("please input addr & data:");
- scanf("%d %d",&addr,&data1);
- head = double_link_insert(head,addr,data1);
- break;
-
- case 2:
- printf("please input old data & new data:");
- scanf("%d %d",&data1,&data2);
- double_link_modify(head,data1,data2);
- break;
-
- case 3:
- printf("please input addr:");
- scanf("%d",&addr);
- head = double_link_delete(head,addr);
- break;
-
- case 4:
- double_link_print(head);
- break;
-
- case 5:
- printf("please input addr:");
- scanf("%d",&addr);
- double_link_find(head,addr);
- break;
-
- default:
- printf("input num error!\n");
- break;
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。