[数据结构-3] 双链表及其C语言实现

目录

基本概念

算法时间复杂度

 C语言实现


基本概念

双链表也是线性表中链式存储中的一种, 和单链表不同的是, 它不仅有指向后一个节点的指针next, 还有指向前一个节点的指针prior

头结点的prior等于NULL

双链表的结构和单链表基本一致, 只是比单链表更方便的寻找前一个节点 (但是这并没有在时间复杂度上带来优化)

在插入和删除时,注意前驱指针和后继指针都要发生改变, 和单链表的操作有很大不同

算法时间复杂度

  • 找到某个索引的节点: O(n), (不能随机访问,只能从头开始找)
  • 在头部(如果有头指针)/尾部(如果有尾指针)插入节点: O(1)

  • 在中间某位置插入节点: O(n) (因为需要找到节点的位置)
  • 删除第一个节点(如果有头指针): O(1)
  • 删除最后一个节点(如果有尾指针): O(1)

删除最后一个结点是单链表和双链表最大的区别, 单链表需要O(n), 而双链表只需要O(1),

原因是双链表可以轻松找到指向倒数第二个节点

  • 删除中间某位置的节点: O(n) (也是因为需要找到节点位置)

 C语言实现

/**
 * @file double linked list.c
 * @author xiaoxiao (you@domain.com)
 * @brief 双链表
 * @version 0.1
 * @date 2022-03-03
 * 
 * @copyright Copyright (c) 2022
 * 
 */

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

typedef struct Node {
    struct Node* prior; // 前驱结点
    struct Node* next;  // 后继节点
    int data;
}Node;

typedef Node* PNode;

/**
 * @brief 初始化表头(无数据)
 * 
 * @return PNode 表头
 */
PNode initalList(){
    /** 表头不存储数据*/ 
    PNode pHead = (PNode) malloc(sizeof(Node));
    pHead -> next = NULL;
    pHead -> prior = NULL;
    return pHead;
}

/**
 * @brief 在尾部插入一个元素
 * 
 * @param pHead 链表头
 * @param data 数据值
 */
void insertInTail(PNode pHead, int data){
    
    PNode pCurrent = pHead;
    while(pCurrent -> next != NULL){
        pCurrent = pCurrent -> next;
    }
    pCurrent -> next = (PNode) (malloc(sizeof(Node)));
    pCurrent -> next -> next = NULL;
    pCurrent -> next -> prior = pCurrent;
    pCurrent -> next -> data = data;
}

/**
 * @brief 在任意索引插入一个元素
 * 1是在表头后面(第一个元素)插入
 * 
 * @param pHead 链表头
 * @param index 索引
 * @param data 数据值
 */
bool insertByIndex(PNode pHead, int index, int data){
    PNode pCurrent = pHead;
    int i = 1;
    while(pCurrent != NULL){
        if(i == index){
            PNode pNewNode = (PNode)malloc(sizeof(Node)); // 新节点
            pNewNode -> next = pCurrent -> next;
            if(pNewNode -> next != NULL){
                pNewNode -> next -> prior = pNewNode;
            }
            pNewNode -> prior = pCurrent;
            pCurrent -> next = pNewNode;
            pNewNode -> data = data;
            return true;
        }
        pCurrent = pCurrent -> next;
        i ++;
    }
    printf("索引大于链表长度+1\n");
    return false;
}

/**
 * @brief 删除尾部元素
 * 
 * @param pHead 链表头
 */
bool deleteTail(PNode pHead){
    if(pHead -> next == NULL){
        printf("链表为空, 无法删除节点");
        return false;
    }
    PNode pCurrent = pHead;
    PNode pPrev = NULL;
    while(pCurrent -> next != NULL){
        pPrev = pCurrent;
        pCurrent = pCurrent -> next;
    }
    pPrev -> next = NULL;
    free(pCurrent);
    return true;
}

bool deleteByIndex(PNode pHead, int index){
    PNode pCurrent = pHead;
    for(int i = 1; i < index; i++){
        if(pCurrent -> next != NULL){
            pCurrent = pCurrent -> next;
        }
        else{
            printf("索引大于链表长度\n");
            return false;
        }
    }
    if(pCurrent -> next == NULL){ // 这就是最后一个节点
        printf("索引大于链表长度\n");
        return false;
    }
    PNode pNext = pCurrent -> next -> next;
    free(pCurrent -> next);
    pCurrent -> next = pNext;
    pNext -> prior = pCurrent;
    return true;
}

/**
 * @brief 打印链表
 * 
 * @param pHead 链表头
 */
void printList(PNode pHead){
    PNode pCurrent = pHead -> next;
    printf("打印链表: ");
    while(pCurrent != NULL){
        printf("%d ", pCurrent -> data);
        pCurrent = pCurrent -> next;
    }   
}

int main(){
    printf("----------------\n");
    PNode pHead = initalList();
    insertInTail(pHead, 2);
    insertInTail(pHead, 4);
    deleteByIndex(pHead, 1);
    insertByIndex(pHead, 2, 5);
    insertInTail(pHead, 10);
    printList(pHead);
    printf("\n----------------\n");
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值