目录
基本概念
双链表也是线性表中链式存储中的一种, 和单链表不同的是, 它不仅有指向后一个节点的指针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;
}