双向链表的一些基本操作

双向链表

  • 前面的博客向大家介绍了单链表,我们发现单链表在进行查询、删除、添加、修改链表的值时都需要遍历整个链表,这样无疑增加了对链表操作的时间复杂度。而双向链表由于有一个prev指针,这样可以更快的找到前一个节点,减小了时间复杂度,但是,相对应的,由于多开辟了个新的指针,会增加空间复杂度。单链表和双向链表就是一个用空间换时间的例子
  • 比如快餐店订餐时就适合单链表,因为一般领餐后不需要叫上一个顾客;设计系统流程的时候就可以用双链表,因为经常查看前一流程和后一流程,使用时要看具体的情况。

下面我将介绍双向链表的一些基本操作。
首先,我们来看一个双向链表:
这里写图片描述

将x节点插入、修改、删除双向链表都只需找到要修改位置的前后节点,然后分别修改两对指针:prev和next即可。

一些基本操作的代码如下:

//DLinkList.h
#pragma once
#include<stdio.h>
#include<unistd.h>
#include<stddef.h>
#include<stdlib.h>

#define TestType printf("\n###################################### %s ########################################\n",__FUNCTION__)

#define DLinkNodeType char

typedef struct DLinkNode{
    DLinkNodeType data;
    struct DLinkNode* prev;
    struct DLinkNode* next;
}DLinkNode;

//初始化链表
void DLinkListInit(DLinkNode** phead);

//创建新的节点
DLinkNode* DLinkListCreateNode(DLinkNodeType value);

//打印双向链表
void DLinkListPrint(DLinkNode* head,const char* msg);

//尾插
void DLinkListPushBack(DLinkNode* head,DLinkNodeType value);

//头插
void DLinkListPushFront(DLinkNode* head,DLinkNodeType value);

//尾删
void DLinkListPopBack(DLinkNode* head);

//头删
void DLinkListPopFront(DLinkNode* head);

//在指定位置后插入
void DLinkListInsert(DLinkNode* head,DLinkNode* pos,DLinkNodeType value);

//寻找节点
DLinkNode* DLinkListFind(DLinkNode* head,DLinkNodeType to_find);

//删除指定位置的节点
void DLinkListErasePos(DLinkNode* head,DLinkNode* pos);

//删除指定值的节点
void DLinkListEraseValue(DLinkNode* head,DLinkNodeType to_delete);

//销毁链表
void DestroyDLinkList(DLinkNode** phead);

//求链表长度
size_t DLinkListSize(DLinkNode* head);

//在指定位置前插入节点
void DLinkListInsertBefore(DLinkNode* head,DLinkNode* pos,DLinkNodeType value);
//DLinkList.c
#include"DLinkList.h"

DLinkNode* DLinkListCreateNode(DLinkNodeType value){
    DLinkNode* new_node = (DLinkNode*)malloc(sizeof(DLinkNode));
    new_node->data = value;
    new_node->next = new_node;
    new_node->prev = new_node;
    return new_node;
}

void DLinkListDestroyNode(DLinkNode* to_delete){
    free(to_delete);
}

void DLinkListInit(DLinkNode** phead){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        return;
    }
    *phead = DLinkListCreateNode('0');
    return;
}

void DLinkListPrint(DLinkNode* head,const char* msg){
    if(head == NULL){
        printf("链表不存在!非法输入!\n");
        return;
    }
    printf("[ %s ]:\n",msg);
    DLinkNode* cur = head;
    if(cur->next == head){
        printf("[%c][%p]\n",cur->data,cur);
        return;
    }
    printf("[%c][%p]<=>",cur->data,cur);
    cur = cur->next;
    while(cur != head){
        printf("[%c][%p]<=>",cur->data,cur);
        cur = cur->next;
    }
    printf("[%c][%p]\n",cur->data,cur);
    return;
}

void DLinkListPushBack(DLinkNode* head,DLinkNodeType value){
    if(head == NULL){
        return;
    }
    DLinkNode* new_node = DLinkListCreateNode(value);
    DLinkNode* cur = head->prev;
    cur->next = new_node;
    new_node->prev = cur;
    new_node->next = head;
    head->prev = new_node;
    return;
}

void DLinkListPushFront(DLinkNode* head,DLinkNodeType value){
    if(head == NULL){
        return;
    }
    DLinkNode* new_node = DLinkListCreateNode(value);
    DLinkNode* tmp = head->next;
    head->next = new_node;
    new_node->prev = head;
    new_node->next = tmp;
    tmp->prev = new_node;
    return;
}


void DLinkListPopBack(DLinkNode* head){
    if(head == NULL){
        return;
    }
    if(head->next == head){
        printf("无法删除头结点!\n");
        return;
    }
    DLinkNode* to_delete = head->prev;
    to_delete->prev->next = head;
    head->prev = to_delete->prev;
    DLinkListDestroyNode(to_delete);
}

void DLinkListPopFront(DLinkNode* head){
    if(head == NULL){
        return;
    }
    if(head->next == head){
        printf("无法删除头结点!\n");
        return;
    }
    DLinkNode* to_delete = head->next;
    DLinkNode* to_delete_next = to_delete->next;
    head->next = to_delete_next;
    to_delete_next->prev = head;
    DLinkListDestroyNode(to_delete);
}

DLinkNode* DLinkListFind(DLinkNode* head,DLinkNodeType to_find){
    if(head == NULL){
        return NULL;
    }
    DLinkNode* cur = head->next;
    while(cur != head){
        if(cur->data == to_find){
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

//pos之后插入节点
void DLinkListInsert(DLinkNode* head,DLinkNode* pos,DLinkNodeType value){
    if(head == NULL || pos == NULL){
        return;
    }
    DLinkNode* new_node = DLinkListCreateNode(value);
    DLinkNode* pos_next = pos->next;
    pos->next = new_node;
    new_node->prev = pos;
    new_node->next = pos_next;
    pos_next->prev = new_node;
    return;
}

//pos之前插入节点
void DLinkListInsertBefore(DLinkNode* head,DLinkNode* pos,DLinkNodeType value){
    if(head == NULL || pos == NULL){
        return;
    }
    DLinkNode* pos_prev = pos->prev;
    DLinkNode* new_node = DLinkListCreateNode(value);
    pos_prev->next = new_node;
    new_node->prev = pos_prev;
    new_node->next = pos;
    pos->prev = new_node;
    return;
}

//删除指定位置的节点
void DLinkListErasePos(DLinkNode* head,DLinkNode* pos){
    if(head == NULL || pos == NULL){
        return;
    }
    DLinkNode* pos_prev = pos->prev;
    DLinkNode* pos_next = pos->next;
    pos_prev->next = pos_next;
    pos_next->prev = pos_prev;
    DLinkListDestroyNode(pos);
    return;
}

//删除指定值的节点
void DLinkListEraseValue(DLinkNode* head,DLinkNodeType to_delete){
    if(head == NULL){
        return;
    }
    DLinkNode* to_delete_pos = DLinkListFind(head,to_delete);
    DLinkListErasePos(head,to_delete_pos);
    return;
}

//销毁链表
void DestroyDLinkList(DLinkNode** phead){
    if(phead == NULL){
        return;
    }
    if(*phead == NULL){
        return;
    }
    DLinkNode* cur = (*phead)->next;
    while(cur != *phead){
        DLinkListErasePos(*phead,cur);
        cur = (*phead)->next;
    }
    DLinkListDestroyNode(*phead);
    *phead = NULL;
    return;
}

size_t DLinkListSize(DLinkNode* head){
    if(head == NULL){
        return 0;
    }
    DLinkNode* cur = head->next;
    size_t count = 0;
    while(cur != head){
        count++;
        cur = cur->next;
    }
    return count;
}
//测试函数main.c
#include"DLinkList.h"

void TestDLinkListInit(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPrint(head,"初始化链表");
    return;
}

void TestDLinkListPushBack(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    return;
}

void TestDLinkListPushFront(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushFront(head,'a');
    DLinkListPushFront(head,'b');
    DLinkListPushFront(head,'c');
    DLinkListPushFront(head,'d');
    DLinkListPrint(head,"头插abcd");
}

void TestDLinkListPopBack(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPopBack(head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    DLinkListPopBack(head);
    DLinkListPrint(head,"尾删d");
    return;
}

void TestDLinkListPopFront(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPopFront(head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    DLinkListPopFront(head);
    DLinkListPrint(head,"头删a");
    return;
}

void TestDLinkListInsert(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    DLinkNode* pos = DLinkListFind(head,'c');
    DLinkListInsert(head,pos,'x');
    DLinkListPrint(head,"c后插入x");
    DLinkNode* pos2 = DLinkListFind(head,'d');
    DLinkListInsert(head,pos2,'y');
    DLinkListPrint(head,"d后插入y");
    return;
}

void TestDLinkListInsertBefore(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    DLinkNode* pos_c = DLinkListFind(head,'c');
    DLinkListInsertBefore(head,pos_c,'x');
    DLinkListPrint(head,"c前插入x");
    DLinkNode* pos_a = DLinkListFind(head,'a');
    DLinkListInsertBefore(head,pos_a,'y');
    DLinkListPrint(head,"a前插入y");
    return;
}

void TestDLinkListErasePos(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    DLinkNode* pos_c = DLinkListFind(head,'c');
    DLinkListInsert(head,pos_c,'x');
    DLinkListPrint(head,"c后插入x");
    DLinkNode* pos_x = DLinkListFind(head,'x');
    DLinkListErasePos(head,pos_x);
    DLinkListPrint(head,"删除x");
    DLinkNode* pos_d = DLinkListFind(head,'d');
    DLinkListInsert(head,pos_d,'y');
    DLinkListPrint(head,"d后插入y");
    DLinkNode* pos_y = DLinkListFind(head,'y');
    DLinkListErasePos(head,pos_y);
    DLinkListPrint(head,"删除y");
    return;
}

void TestDLinkListEraseValue(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    DLinkNode* pos_c = DLinkListFind(head,'c');
    DLinkListInsert(head,pos_c,'x');
    DLinkListPrint(head,"c后插入x");
    DLinkListEraseValue(head,'x');
    DLinkListPrint(head,"删除x");
    return;
}

void TestDestroyDLinkList(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPrint(head,"尾插abcd");
    DestroyDLinkList(&head);
    DLinkListPrint(head,"销毁链表");
    return;
}

void TestDLinkListSize(){
    TestType;
    DLinkNode* head;
    DLinkListInit(&head);
    DLinkListPushBack(head,'a');
    DLinkListPushBack(head,'b');
    DLinkListPushBack(head,'c');
    DLinkListPushBack(head,'d');
    DLinkListPushBack(head,'e');
    DLinkListPushBack(head,'f');
    size_t size = DLinkListSize(head);
    printf("expect:6,actual:%zu\n",size);
}

int main(){
    TestDLinkListInit();
    TestDLinkListPushBack();
    TestDLinkListPushFront();
    TestDLinkListPopBack();
    TestDLinkListPopFront();
    TestDLinkListInsert();
    TestDLinkListInsertBefore();
    TestDLinkListErasePos();
    TestDLinkListEraseValue();
    TestDestroyDLinkList();
    TestDLinkListSize();
    printf("\n\n\n");
    return 0;
}

最后奉上Makefile

DLinkList:DLinkList.c main.c
    gcc $^ -o $@ -g
.PHONY:clean
clean:
    rm -f DLinkList

由于个人水平有限,以上代码可能有BUG或者不妥之处,欢迎发邮件到我的邮箱(Cyrus_wen@163.vom)批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值