数据结构 链表_双向链表的实现与分析

双向链表的实现与分析

双向链表的组成 :1、数据成员;2、指向下一个元素的next指针;3、指向前一个元素的prev指针。

数据结构DListElmt:代表双向链表中的单个元素(节点)。

数据结构DList:代表双向链表数据结构,该结构的成员同前面介绍的单链表相似。

示例1:双向链表抽象数据类型的头文件

    /*dlist.h*/
    #ifndef  DLIST_H
    #define  DLIST_H  

    /*定义双向链表中的元素*/
    typedef struct DListLemt_
    {
        void *data;
        struct DListElmt_ *prev;
        struct DlistElmt_ *next;
    }DListElmt;  

    /*定义双向链表*/
    typedef struct DList_
    {
        int size;
        int (*match)(const void *key1,const void *key2);
        void (*destroy)(void *data);
        DListElmt *head;
        DlistElmt *tail;
    }DList;  

    /*公共接口*/
    void dlist_init(DList *list,void (*destroy)(void *data)) ;
    void dlist_destroy(DList *list);
    int dlist_ins_next(DList *list,DListElmt *element,const void *data);
    int dlist_ins_prev(Dlist *list,DListElmt *element,const void *data);
    int dlist_remove(DList *list,DlistElmt *element,void **data);  

    #define dlist_size(list)((list)->size)
    #define dlist_head(list)((list)->head)
    #define dlist_tail(list)((list)->tail)
    #define dlist_is_head(element)((element)->prev == NULL ? 1 : 0)
    #define dlist_is_tail(element)((element)->next == NULL ? 1 : 0)
    #define dlist_data(element)((element)->data)
    #define dlist_next(element)((element)->next)
    #define dlist_prev(element)((element)->prev)  

    #endif  

示例2: 双向链表抽象数据类型的实现

    /*dlist.c*/
    #include <stdio.h>
    #include <string.h>  

    #include "dlist.h"  

    /*dlist_init    初始化双向链表*/
    void dlist_init(DList *list,void(*destroy)(void *data))
    {
        list->size = 0;
        list->destroy = destroy;
        list->head = NULL;
        list->tail = NULL;  

        return ;
    }  

    /*dlist_destroy  销毁双向链表*/
    void dlist_destroy(DList *list)
    {
        void *data;  

        /*移除每一个元素*/
        while(dlist_size(list)>0)
        {
            if(dlist_remove(list,dlist_tail(list),(void **)&data)==0
               && list->destroy != NULL)
               {
                   /*调用一个用户自定义函数释放动态分配的数据*/
                   list->destroy(data);
               }
        }  

        /*不再允许其他操作,清除链表结构*/
        memset(list,0,sizeof(DList));
        return;
    }  

    /*dlist_ins_next  将元素插入指定元素之后*/
    int dlist_ins_next(DList *list,DListElmt *element,const void *data)
    {
        DListElmt *new_element;  

        /*除非链表为空,否则不允许使用null元素。*/
        if(element == NULL && dlist_size(list) != 0)
            return -1;
        /*为元素分配空间*/
        if((new_element=(DListElmt*)malloc(sizeof(DListElmt)))==NULL)
            return -1;  

        /*将新元素插入链表*/
        new_element->data = (void*)data;  

        if(dlist_size(list)==0)
        {
            /*链表为空时*/
            list->head = new_element;
            list->head->prev = NULL;
            list->head->next = NULL;
            list->tail = new_element;
        }
        else
        {
            /*链表不为空时*/
            new_element->next = element->next;
            new_element->prev = element;  

            if(element->next == NULL)
                list->tail = new_element;
            else
                element->next->prev=new_element;  

            element->next = new_element;
        }
        list->size++;
        return 0;
    }
    /*dlist_ins_prev*/
    int dlist_ins_prev(DList *list,DListElmt *element,const void *data)
    {
        DListElmt *new_element;  

        /*除非链表为空,否则不允许element为null*/
        if(element == NULL && dlist_size(list)!=0)
            return -1;  

        /*为新元素分配存储*/
        if((new_element=(DlistElmt *)malloc(sizeof(DListElmt))==NULL)
            return -1;  

        /*insert the new element into the list*/
        new_element->data=(void *data);
        if(dlist_size(list)==0)
        {
            /*链表为空*/
            list->head = new_element;
            list->head->prev = NULL;
            list->tail->tail = NULL;
            list->tail = new_element;
        }
        else
        {
            /*链表非空*/
            new_element_next = element;
            new_element_prev = element_prev;  

            if(element->prev == NULL)
                list->head = new_element;
            else
                element->prev->next = new_element;  

            element->prev = new_element;
        }
        /*改变链表中结点数量*/
        list->size++;
        return 0;
    }  

     /*dlist_remove*/
    int dlist_remove(Dlist *list,DList_Elmt *element,void **data)
    {
        /*不允许移除一个空元素或者从一个空链表中移除元素.*/
        if(element == NULL || dlist_size(list)==0)
            return -1;
        /*移除元素*/
        *data = element->data;  

        if(element == list->head)
        {
            /*从链表的头部移除操作*/
            list->head = element->next;  

            if(list->head == NULL)
                list->tail = NULL;
            else
                element->next->prev = NULL;
        }
        else
        {
            /*从链表其他位置移除元素操作*/
            element->prev->next = element->next;  

            if(element->next == NULL)
                list->tail = element->prev;
            else
                element->next->prev = element->prev;
        }  

        /*释放空间*/
        free(element);
        /*改变链表中结点数量*/
        list->size--;
        return 0;
    }  

时间: 2024-10-11 00:13:13

数据结构 链表_双向链表的实现与分析的相关文章

数据结构 链表_双向链表的接口定义

双向链表介绍 双向链表中的每一个元素都由3部分组成:除了数据成员.next指针外,每个元素还包含一个指向其前驱元素的指针,称为prev指针.双向链表的组成是这样的:将一些元素链接在一起,使得每个元素的next指针都指向其后继的元素,而每个元素的prev指针都指向其前驱元素. 为了标识链表的头和尾,将第一个元素的prev指针和最后一个元素的next指针设置为NULL. 要反向遍历整个双向链表,使用prev指针以从尾到头的顺序连续访问各个元素.当我们知道某个元素存储在链表在的某处时,我们可以选择按何

数据结构 链表_单链表的接口定义

链表可以说是一种最为基础的数据结构.链表由一组元素以一种特定的顺序组合或链接而成,在维护数据的集合时很有用.这一点同我们常用的数组很相似.然而,链表在很多情况下比数组更有优势.特别是在执行插入和删除操作时链表拥有更高的效率.链表需要动态的开辟存储空间,也就是存储空间是在程序运行时分配的.由于在很多应用中数据的大小在编译时并不能确定,因此这种动态分配空间的特性也是链表的一个优点. 单链表介绍 单链表(简称为链表)由各个元素之间通过一个指针彼此链接起来而组成.每个元素包含两个部分:数据成员和一个称为

【 C# 数据结构】(一) -------------------------- 泛型带头节点的单链表,双向链表实现

在编程领域,数据结构与算法向来都是提升编程能力的重点.而一般常见的数据结构是链表,栈,队列,树等.事实上C#也已经封装好了这些数据结构,在头文件 System.Collections.Generic 中,直接创建并调用其成员方法就行.不过我们学习当然要知其然,亦知其所以然. 本文实现的是链表中的单链表和双向链表,并且实现了一些基本方法 一. 定义一个链表接口 MyList 接口里声明了我们要实现的方法: interface MyList<T> { int GetLength(); //获取链表

数据结构之_单链表的实现

数据结构之_单链表的实现 1.基本概念 链式存储定义 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息. 单链表 线性表的链式存储结构中,每个节点中只包含一个指针域,这样的链表叫单链表. 通过每个节点的指针域将线性表的数据元素按其逻辑次序链接在一起(如图). 概念解释: 表头结点 链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 数据结点 链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息

数据结构 -- 链表&amp;双向链表

链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域. 使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理.但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大.链表最明显的好处就是,常规数组排列关

单向链表和双向链表的原理及其相关实现

(一)什么是链表? 链表是线性表的一种,所谓的 线性表包含顺序线性表和链表,顺序线性表是用数组实现的,在内存中有顺序排列,通过改变数组大小实现.而链表不是用顺序实现的,用指针实现,在内存中不连 续.意思就是说,链表就是将一系列不连续的内存联系起来,将那种碎片内存进行合理的利用,解决空间的问题. 所以,链表允许插入和删除表上任意位置上的节点,但是不允许随即存取.链表有很多种不同的类型:单向链表.双向链表及循环链表. 1.那么先从单向链表着手,先看看单向链表的模拟图: 单向链表包含两个域,一个是信息

线性链表的双向链表——java实现

.线性表链式存储结构:将采用一组地址的任意的存储单元存放线性表中的数据元素. 链表又可分为: 单链表:每个节点只保留一个引用,该引用指向当前节点的下一个节点,没有引用指向头结点,尾节点的next引用为null. 循环链表:一种首尾相连的链表. 双向链表:每个节点有两个引用,一个指向当前节点的上一个节点,另外一个指向当前节点的下一个节点. 下面给出线性表双向链表的实现:java中LinkedList是线性表的链式实现,是一个双向链表. import java.util.NoSuchElementE

魔鬼作坊VIP教程第七款_大杀特杀分析来源与CALL吸血鬼课程

教程目录: G-1.大杀特杀完结来源分析-找人物信息基址偏移.G-2.斩杀人物信息基址游戏退出会变化问题.G-3.通过人物信息的一个偏移轻松挖掘出其他相关信息偏移.G-4.超强小技巧快速分析人物所需升级经验偏移. G-5.魔鬼式钩子注入快速斩杀游戏超级权限.G-6.斩杀权限后读取人物信息各种有价值数据.G-7.一招讨伐极强CALL术快速暴杀快捷键技能CALL.G-8.编疯了!几个命令轻松编写调用快捷键技能CALL.G-9.内联疯了!嵌入式编写调用快捷键技能CALL.G-10.饥渴难耐的CE爆出突

ArcGIS for Desktop入门教程_第七章_使用ArcGIS进行空间分析 - ArcGIS知乎-新一代ArcGIS问答社区

原文:ArcGIS for Desktop入门教程_第七章_使用ArcGIS进行空间分析 - ArcGIS知乎-新一代ArcGIS问答社区 1 使用ArcGIS进行空间分析 1.1 GIS分析基础 GIS的六大功能是数据获取.存储.查询.分析.表达.输出.在前面的内容里已经介绍了使用ArcGIS进行数据获取.存储.查询.表达和输出的过程,本章将介绍如何在ArcGIS中进行地理分析.分析是GIS的核心和灵魂,是GIS区别于一般的信息系统.CAD或者电子地图系统的主要标志之一. GIS分析,就是研究