数据结构双链表

由于单链表的插入删除需要利用前驱结点,每次需要遍历寻找不方便,引入双链表

双链表包含prior 和next两个指针,prior非常方便找到他的前驱结点

插入删除时间复杂度变为O(1)

双链表的基本操作

1.插入操作(画图)

        防止断链需要保证顺序,p后继结点的修改要在后继结点相关操作完成

        插入结点的next,p后继结点的prior;

        后插

bool insertdoule(DLnode *p,DLnode *s){
    s->next=p->next;
    if(p->next!=NULL)
        p->next->prior=s;
    s->prior=p;
    p->next=s;
}

      前插:类似后插不保证断链,p的前驱结点修改要在相关操作之后

                s->prior=p->prior p->prior=s 才可以修改 p->prior=s 

2.删除操作(画图)

        删除P的后继结点q

                p->next=q->next;

                q->next->prior=p;

                free(q);

        删除q结点的前驱结点p 类似指向

                q->prior=p->prior;

                p->prior->next=q;

                free(q);

二、循环单链表

        和单链表的区别:最后一个结点的next不指向NULL,指向头结点 从而形成一个环

三、循环双链表

        头结点的prio指向尾结点,尾结点的next指向头结点

四、总结顺序表和链表的比较

        1.存取(读写)方式

              顺序表可以随机存取,也可以顺序存取;链表只能顺序存取

        2.逻辑结构和物理结构

                顺序表(存储):逻辑上相邻的元素在物理上也相邻

                链表(存储):采用链式存储,逻辑相邻,物理不一定相邻,通过指针的链接表示

      3.查找元素

                按值查找顺序表:无序 时间复杂度:O(n) 有序折半查找 时间复杂度O(logn)

                按序查找顺序表:时间复杂度  O(1)

                链表的平均时间复杂度都为O(n)

     4.删除插入元素

                顺序表平均需要移动半个表长

                链表只需要修改指针域 O(1),但指针域浪费空间

     5.空间分配

                顺序表的静态分配:一旦存储空间装满不能扩充

                顺序表的动态分配:虽然可以扩充但是效率过低,没有相当大的连续空间也是分配失败

                链表:只在有需要的时候申请空间。有空间就分配,灵活高效

如何选择最优存储方式:

        1.基于存储:如果不预先知道数据规模,不能采用顺序表。若不考虑存储密度,采用链表

        2.基于运算考虑 若经常的操作是按序号访问做运算,采用顺序表

                                  经常插入删除采用链表

        3.环境考虑:数组实现容易,指针较难。顺序表容易实现

                  

#include <iostream>
//双链表

//定义节点
typedef struct DLnode{
    int data;
    struct DLnode *prior,*next;
}DLnode,*DLinklist;
//
bool initiDlinklist(DLinklist &L){
    L=(DLnode *)malloc(sizeof(DLnode));
    if (L==NULL)
        return false;
    L->next=NULL;
    L->prior=NULL;  //永远指向NULL
    return true;
}

bool empty(DLinklist &L){
    if (L==NULL)
        return true;
    else
        return false;
}
//插入节点
bool insertDlinklist(DLinklist &L,DLnode *s,DLnode *p){
    s->next=p->next;
    if (p->next!=NULL)    //P没后节点
        p->next->prior=s;
    s->prior=p;
    p->next=s;

}
//删除节点
bool deleteDLnode(DLnode *s){
    DLnode *p=s->next;
    if (s==NULL)
        return false;
    if (p==NULL)  //s是否有后继
        return false;
    s->next=p->next;
    if (p->next!=NULL)
        p->next->prior=s;
    free(p);
    return true;


}
//双链表遍历
//往后遍历
//while(p!=NULL){
//     p=p->next;
//}
//往前遍历
//while(p!=NULL){
//    p=p->prior;
// }
//跳过头头节点
//while(p->prior!=NULL){
//     p=p->prior;
//}





int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值