C语言-双向链表

一、双链表

单项链表:表中各结点中都只含有一个指针(游标),且都统一指向后继结点(适合从前往后
双向链表:查找某结点的前驱结点(适合从后往前

指针域(prior):指向当前结点的直接前驱结点;
数据域:存储数据元素;
指针域(next):指向当前结点的直接后继结点;
图示:

1、创建

将新结点的 prior 指针指向直接前驱结点
将直接前驱结点的 next 指针指向新结点
图示:

link* initLine()
{
    // 头指针
    link* head = NULL;
    // 首元结点
    link* temp = malloc(sizeof(link));
    temp->prior = NULL;
    temp->next = NULL;
    temp->data = 1;
    // 头指针指向首元结点
    head = temp;

    for (int i = 2; i < 5; ++i) {
        // 创建新的结点
        link* new = malloc(sizeof(link));
        // prior 指向 直接前驱结点
        new->prior = temp;
        // next 置空
        new->next = NULL;
        new->data = i;
        // 直接前驱结点 指向 新结点
        temp->next = new;
        // 上一个结点指向 新结点(后移一个结点,不然一直都会指向首元结点,没意义)
        temp = temp->next;
    }
    return head;
}

2、添加元素

(不作判断,可自行添加判断条件,位置 为0或小于1 一律插入位置 2,可自行体会为什么)
分三种情况:
表头:(注意有两层逻辑关系)
(1)必需先处理新结点和首元结点之间的指针指向,再处理头指针指向新的首元结点
(2)不要次序颠倒,不然会丢失数据

表中间:(注意有两层逻辑关系)
(1)必需先处理新结点和插入位置前一个结点的直接后继结点(步骤1)之间的指针指向,再处理插入位置的直接前驱结点指向新结点(步骤2)
(2)不要次序颠倒,不然会丢失数据

表尾:(注意有两层逻辑关系)

link* insertLink(link* head, int add, int data)
{
    link* new = malloc(sizeof(link));
    // 初始化结点(也不初始化,直接用)
    new->next = NULL;
    new->prior = NULL;
    new->data = data;
    // 判断插入情况
    if(add == 1){
        new->next = head;
        head->prior = new;
        head = new;
    }else{
        int i = 0;
        link* temp = head;
        // i=1:temp放在if语句之前;add-1:插入位置的 前一个结点 就要停下
        for (i = 1; i < add-1; ++i) {
            temp = temp->next;
            if(temp == NULL){
                printf("插入位置有误\n");
                break;
            }
        }
        // 判断插入元素是否存在
        if(temp){
            // 判断插入元素是否在 链尾
            if(temp->next == NULL){
                new->prior = temp;
                temp->next = new;
            }else{
                // 表中间的插入
                new->next = temp->next;
                temp->next->prior = new;
                temp->next = new;
                new->prior = temp;
            }
        }
    }
    return head;
}

3、删除元素

分三种情况:
表头:
我也不是很清楚,尴尬了;头指针我不知道删除时该怎么操作,不知道我的处理方法会不会出现野指针

表中间:
表尾:

link* delLink(link* head,int data)
{
    link* temp = head;
    while(temp){
        if(temp->data == data){
            // 头部删除
            if(temp->prior == NULL){
                // 第一种
                head = head->next;
                head->prior->next = NULL;
                head->prior = NULL;
                free(temp);
                return head;
                // 第二种方法
//                link* del = temp;
//                temp = temp->next;
//                temp->prior = NULL;
//                // 结构体的指针域置空
//                del->next = NULL;
//                // 释放首元结点内存
//                free(del);
//                // 头指针置空
//                head = NULL;
//                // 首元结点已经没有,返回 直接后继元素
//                return temp;
            }
            // 尾部删除
            if(temp->next == NULL){
                // 先将有逻辑关系的指针 置空再释放内存,避免出现野指针
                temp->prior->next = NULL;
                temp->prior = NULL;
                free(temp);
                return head;
            }
            temp->prior->next = temp->next;
            temp->next->prior = temp->prior;
            free(temp);
            return head;
        }
        temp = temp->next;
    }
    printf("链表中无该元素\n");
    return head;
}

4、查找元素

int selectElem(link* head,int elem)
{
    link* temp = head;
    int i = 1;
    while (temp){
        if(temp->data == elem){
            return i;
        }
        i++;
        temp = temp->next;
    }
    return -1;
}

5、更换元素

void amendElem(link* head,int oldElem,int newElem)
{
    while (head){
        if(head->data==oldElem){
            head->data = newElem;
            return;
        }
        head = head->next;
    }
    if(head == NULL){
        printf("没有找到要 更改 的元素\n");
    }
}

6、打印

void display(link* head)
{
    while(head){
        printf("%d ",head->data);
        head = head->next;
    }
    printf("\n");
}

7、全部代码

//
// Created by 醉人饮梦 on 2023/2/25.
//

#include <stdio.h>
#include <stdlib.h>

typedef struct link{
    struct link* prior;
    int data;
    struct link* next;
}link;

// 初始化
link* initLink(link* head)
{
    // 首元结点
    link* temp = malloc(sizeof(link));
    temp->prior = NULL;
    temp->next = NULL;
    temp->data = 1;
    // 头指针指向首元结点
    head = temp;

    for (int i = 2; i < 5; ++i) {
        // 创建新的结点
        link* new = malloc(sizeof(link));
        // prior 指向 直接前驱结点
        new->prior = temp;
        // next 置空
        new->next = NULL;
        new->data = i;
        // 直接前驱结点 指向 新结点
        temp->next = new;
        // 上一个结点指向 新结点(后移一个结点,不然一直都会指向首元结点,没意义)
        temp = temp->next;
    }
    return head;
}

// 添加元素
link* insertLink(link* head, int add, int data)
{
    link* new = malloc(sizeof(link));
    // 初始化结点(也不初始化,直接用)
    new->next = NULL;
    new->prior = NULL;
    new->data = data;
    // 判断插入情况
    if(add == 1){
        new->next = head;
        head->prior = new;
        head = new;
    }else{
        int i = 0;
        link* temp = head;
        // i=1:temp放在if语句之前;add-1:插入位置的 前一个结点 就要停下
        for (i = 1; i < add-1; ++i) {
            temp = temp->next;
            if(temp == NULL){
                printf("插入位置有误\n");
                break;
            }
        }
        // 判断插入元素是否存在
        if(temp){
            // 判断插入元素是否在 链尾
            if(temp->next == NULL){
                new->prior = temp;
                temp->next = new;
            }else{
                // 表中间的插入
                new->next = temp->next;
                temp->next->prior = new;
                temp->next = new;
                new->prior = temp;
            }
        }
    }
    return head;
}

// 删除元素
link* delLink(link* head,int data)
{
    link* temp = head;
    while(temp){
        if(temp->data == data){
            // 头部删除
            if(temp->prior == NULL){
                // 提交 保留 首元结点位置,后面释放内存用
                link* del = temp;
                temp = temp->next;
                temp->prior = NULL;
                // 结构体的指针域置空
                del->next = NULL;
                // 释放首元结点内存
                free(del);
                // 头指针置空
                head = NULL;
                // 首元结点已经没有,返回 直接后继元素
                return temp;
            }
            // 尾部删除
            if(temp->next == NULL){
                // 先将有逻辑关系的指针 置空再释放内存,避免出现野指针
                temp->prior->next = NULL;
                temp->prior = NULL;
                free(temp);
                return head;
            }
            temp->prior->next = temp->next;
            temp->next->prior = temp->prior;
            free(temp);
            return head;
        }
        temp = temp->next;
    }
    printf("链表中无该元素\n");
    return head;
}

// 查找元素
int selectElem(link* head,int elem)
{
    link* temp = head;
    int i = 1;
    while (temp){
        if(temp->data == elem){
            return i;
        }
        i++;
        temp = temp->next;
    }
    return -1;
}

// 更改
void amendElem(link* head,int oldElem,int newElem)
{
    while (head){
        if(head->data==oldElem){
            head->data = newElem;
            return;
        }
        head = head->next;
    }
    if(head == NULL){
        printf("没有找到要 更改 的元素\n");
    }
}

// 打印
void display(link* head)
{
    while(head){
        printf("%d ",head->data);
        head = head->next;
    }
    printf("\n");
}

int main()
{
    link* head = NULL;
    head = initLink(head);
    printf("数据依次为:\n");
    display(head);
    printf("在位置 2 插入 7 :\n");
    head = insertLink(head, 2, 7);
    display(head);
    printf("删除元素 2:\n");
    head = delLink(head, 2);
    display(head);
    printf("查找元素 3:%d\n",selectElem(head, 3));
    printf("更改 元素 7 为 9:\n");
    amendElem(head, 7, 9);
    display(head);

    return 0;
}

结语

个人记录学习所用,如有错误之处还请指出,谢谢

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值