zoukankan      html  css  js  c++  java
  • 数据结构(一)线性表双向链表

    (一)定义

    双向链表是在单链表的每个结点中,再设置一个纸箱其前驱结点的指针域

    (二)结点结构

    typedef struct Node
    {
        ElemType data;
        struct Node* prior;    //直接前驱指针
        struct Node* next;    //直接后继指针
    }Node;
    
    typedef struct Node* CLinkList;

    (三)双向链表结构

    双向循环链表

    带有头结点的空链表

    带有头结点的数据链表

    对于非循环的,直接将头结点的直接前驱指针置为空,将尾结点的直接后驱结点置为空即可

    (四)实现双向链表

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <math.h>
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    
    typedef char ElemType;
    typedef int Status;
    
    typedef struct Node
    {
        ElemType data;
        struct Node* prior;    //直接前驱指针
        struct Node* next;    //直接后继指针
    }Node;
    
    typedef struct Node* DLinkList;
    
    //四个基本操作,初始化,清空,获取长度,是否为空
    Status InitList(DLinkList* Dl);
    Status ClearList(DLinkList* Dl);
    int GetLength(DLinkList Dl);
    Status EmptyList(DLinkList Dl);
    
    //四个插入,程序,删除操作
    Status GetElem(DLinkList Dl, int i, ElemType* e);
    int LocateElem(DLinkList Dl, ElemType e);
    Status InsertList(DLinkList* Dl, int i, ElemType e);
    Status DeleteList(DLinkList* Dl, int i, ElemType* e);
    
    //打印链表
    void PrintList(DLinkList Dl, int i);
    
    int main()
    {
        DLinkList dbList;
        ElemType e='A';
        int i = 0;
        
        InitList(&dbList);//初始化链表
        
        for (; i < 26;i++)    //插入数据
        {
            //InsertList(&dbList, -1, e + i);    //尾插法
            InsertList(&dbList, GetLength(dbList)+1, e + i);    //头插法
        }
    
        PrintList(dbList, 3);
        PrintList(dbList, -3);
    
        system("pause");
        return 0;
    }
    
    
    //四个基本操作,初始化,清空,获取长度,是否为空
    //创建一个带有头结点的双向链表
    Status InitList(DLinkList* Dl)
    {
        *Dl = (DLinkList)malloc(sizeof(Node));
        if (*Dl == NULL)
            return ERROR;
        (*Dl)->next = (*Dl)->prior = (*Dl);    //都指向头结点,虽然这里数据data为char,也是可以存储链表长度的,但是这里不使用
        return OK;
    }
    
    //清空双向链表,头结点也释放掉
    Status ClearList(DLinkList* Dl)
    {
        DLinkList Dlist = *Dl;
        DLinkList q;
    
        if (Dlist == NULL)
            return ERROR;
    
        //先将尾结点的next指针置为空,一会作为判断循环退出条件
        Dlist->prior->next = NULL;
        while (Dlist)
        {
            q = Dlist;
            Dlist = Dlist->next;
            free(q);
        }
    
        return OK;
    }
    
    //获取链表长度,不含头结点,使用一条单向指针域即可
    int GetLength(DLinkList Dl)
    {
        DLinkList cur = Dl->next;
        int length = 0;
        while (cur!=Dl)
        {
            cur = cur->next;
            length++;
        }
        return length;
    }
    
    //判断是否链表为空,判断头结点一个指针是否指向自己就可以
    Status EmptyList(DLinkList Dl)
    {
        if (Dl->prior == Dl)
            return TRUE;
        return FALSE;
    }
    
    //四个插入,程序,删除操作
    //根据索引获取数据,支持双向索引
    Status GetElem(DLinkList Dl, int i, ElemType* e)
    {
        int j = 0;
        DLinkList cur = Dl;
        if (e == NULL||i==0)
            return ERROR;
        for (; j < abs(i);j++)
        {
            if (i < 0)
                cur = cur->prior;
            else
                cur = cur->next;
        }
        *e = cur->data;
        return OK;
    }
    
    //按照元素进行查找,单向正向查找
    int LocateElem(DLinkList Dl, ElemType e)
    {
        DLinkList cur = Dl->next;
        int index=1;
        while (cur->data != e&&cur != Dl)
        {
            cur = cur->next;
            index++;
        }
        if (cur == Dl)
            return 0;
        return index;
    }
    
    //支持双向插入
    Status InsertList(DLinkList* Dl, int i, ElemType e)
    {
        DLinkList cur = *Dl;
        DLinkList newNode;
        int j = 0;
        if (*Dl == NULL || abs(i) > GetLength(*Dl) + 1 || i == 0)
            return ERROR;
        for (; j < abs(i);j++)    //找到他的后一个节点,一会向前推
        {
            if (i < 0)
                cur = cur->prior;
            else
                cur = cur->next;
        }
    
        //创建一个新的结点
        newNode = (DLinkList)malloc(sizeof(Node));
        newNode->data = e;
    
        if (i<0)
        {
            newNode->next = cur->next;
            newNode->prior = cur;
            cur->next->prior = newNode;
            cur->next = newNode;
        }
        else
        {
            newNode->next = cur;
            newNode->prior = cur->prior;
            cur->prior->next = newNode;
            cur->prior = newNode;
        }
        return OK;
    }
    
    //支持双向删除
    Status DeleteList(DLinkList* Dl, int i, ElemType* e)
    {
        DLinkList cur = *(Dl);
        DLinkList oldNode;
        int j = 0;
        if (*Dl == NULL || abs(i) > GetLength(*Dl) || i == 0 || e == NULL)
            return ERROR;
        for (; j < abs(i); j++)    //找到要删除的结点
        {
            if (i < 0)
                cur = cur->prior;
            else
                cur = cur->next;
        }
        //赋值
        *e = cur->data;
        oldNode = cur;
        //开始交换指针顺序
        oldNode->prior->next = oldNode->next;
        oldNode->next->prior = oldNode->prior;
        free(oldNode);
        return OK;
    }
    
    
    //打印链表,支持双向打印,其实在main方法中稍微调整传入的结点也可以实现
    void PrintList(DLinkList Dl, int i)
    {
        DLinkList cur = Dl;
        DLinkList start;
        int j = 0;
    
        if (i==0)    //若是输入0,按照正向找到第一个结点进行输出即可
            cur = cur->next;
    
        for (; j < abs(i); j++)    //找到要开始打印的最开始那个结点
        {
            if (i < 0)
                cur = cur->prior;
            else
                cur = cur->next;
        }
        start = cur;    //找到最开始打印的那个结点
        while (cur->next!=start)    //进行判断结点
        {
            if (cur!=Dl)    //不打印头结点
                printf("%c ", cur->data);
            cur = cur->next;
        }
        if (cur != Dl)
            printf("%c", cur->data);
        printf("
    ");
    }

    (五)打印预览

    (六)总结

    双向链表相对于单链表来说,要复杂些,多了个直接前驱指针,对于初入,删除考虑的指针交换需要格外小心。而且占用空间也增加了。
    但是他有良好的对称性,是对于某个结点的前后结点的操作,带来了方便,提高了算法时间性能。也就是使用空间来换取时间。
    原来单链表要寻找某个结点的前一个节点的时间复杂度是O(n),使用双向链表去查找前一个节点的时间复杂度是O(1)
  • 相关阅读:
    一套代码小程序&Web&Native运行的探索05——snabbdom
    一套代码小程序&Web&Native运行的探索04——数据更新
    一套代码小程序&Web&Native运行的探索03——处理模板及属性
    一套代码小程序&Web&Native运行的探索02
    微信小程序开发07-列表页面怎么做
    微信小程序开发06-一个业务页面的完成
    微信小程序开发05-日历组件的实现
    微信小程序开发04-打造自己的UI库
    微信小程序开发03-这是一个组件
    30分钟ES6从陌生到熟悉
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9429664.html
Copyright © 2011-2022 走看看