欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

线性表(List)---链式存储结构(双向链表)

程序员文章站 2022-06-07 08:10:16
...

双向链表设计与实现


双向链表的介绍

双向链表定义: 在单链表的结点中增加一个指向其前驱的pre指针。
线性表(List)---链式存储结构(双向链表)
双向链表设计意义: 方便逆序访问链表中的元素(O(n))。
单链表中的逆序访问:

len = LinkList_Length(list);
for (i = len - 1; len >= 0; i++) //O(n)
{   
LinkListNode *p = LinkList_Get(list, i); //O(n)
//访问数据元素p中的元素
}

双向链表的设计

定义一个结构体指针用来存储指针与指针之间的关系:

typedef struct DLinkListNode
{
    struct DLinkListNode *next;
    struct DLinkListNode *pre;
}DLinkListNode;

定义一个头结点用来存储链表:

typedef struct _tag_DLinkList
{
    DLinkListNode header;
    DLinkListNode *slider;//游标
    int length;
}TDLinkList;

数据元素定义实例:

typedef struct Value
{
    DLinkListNode node;
    int v;
}Value;

双向链表新增操作

  • 获取当前游标指向的数据元素
  • 将游标重置指向链表中的第一个数据元素
  • 将游标移动指向到链表中的下一个数据元素
  • 将游标移动指向到链表中的上一个数据元素
  • 直接指定删除链表中的某个数据元素

双向链表重要算法

  • 双向链表插入算法
    线性表(List)---链式存储结构(双向链表)
  • 双向链表删除算法
    线性表(List)---链式存储结构(双向链表)

双向链表的优缺点

  • 优点: 双向链表在单链表的基础上增加了指向前驱的指针;功能上双向链表可以完全取代单链表的使用;循环链表的Next、Pre和Current操作可以高效的遍历链表中的所有元素。
  • 缺点: 代码复杂。

双向链表的实现

DLinkList.h

#ifndef  _DLINKLIST_H_
#define  _DLINKLIST_H_

typedef void DLinkList;
typedef struct DLinkListNode
{
    struct DLinkListNode *next;
    struct DLinkListNode *pre;
}DLinkListNode;

//创建双向链表
DLinkList *DLinkList_Create();

//销毁双向链表
void DLinkList_Destroy(DLinkList *list);

//清空双向链表
void DLinkList_Clear(DLinkList *list);

//获取双向链表长度
int DLinkList_Length(DLinkList *list);

//向第pos位置char如元素node
int DLinkList_Insert(DLinkList *list, DLinkListNode *node, int pos);

//获取第pos位置的元素
DLinkListNode *DLinkList_Get(DLinkList *list, int pos);

//删除第pos位置的元素
DLinkListNode *DLinkList_Delete(DLinkList *list, int pos);

//获取当前游标的元素
DLinkListNode *DLinkList_Current(DLinkList *list);

//将游标重置指向链表的第一个位置元素
DLinkListNode *DLinkList_Rset(DLinkList *list);

//将游标移动指向到链表下一个位置元素
DLinkListNode *DLinkList_Next(DLinkList *list);

//将游标移动指向到链表上一个位置元素
DLinkListNode *DLinkList_Pre(DLinkList *list);

//直接删除指定链表中的某个元素
DLinkListNode *DLinkList_DeleteNode(DLinkList *list, DLinkListNode *node);

#endif//DLinkList.h

DLinkList.c

#include "DLinkList.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct _tag_DLinkList
{
    DLinkListNode header;
    DLinkListNode *slider;//游标
    int length;
}TDLinkList;

//创建双向链表
DLinkList *DLinkList_Create()
{
    TDLinkList *ret = (TDLinkList *)malloc(sizeof(TDLinkList));
    if(ret==NULL)
    {
        printf("func DLinkList_Create()(ret==NULL) err\n");
        return ret;
    }
//  memset(ret, 0, sizeof(ret));
    ret->header.next = NULL;
    ret->header.pre = NULL;
    ret->slider = NULL;
    ret->length = 0;

    return ret;
}

//销毁双向链表
void DLinkList_Destroy(DLinkList *list)
{
    if (list == NULL)
    {
        return;
    }
    free(list);
    return ;
}

//清空双向链表
void DLinkList_Clear(DLinkList *list)
{
    TDLinkList *tlist=(TDLinkList *)list;
    if (list == NULL)
    {
        printf("func DLinkList_Clear() (list == NULL) err\n");
        return;
    }

    tlist->header.next = NULL;
    tlist->header.pre = NULL;
    tlist->slider = NULL;
    tlist->length = 0;
    return ;
}

//获取双向链表长度
int DLinkList_Length(DLinkList *list)
{
    int ret = 0;
    TDLinkList *tlist = (TDLinkList *)list;
    if (list == NULL)
    {
        ret = -1;
        printf("func DLinkList_Length()(list == NULL) err:%d\n",ret);
        return ret;
    }
    ret = tlist->length;

    return ret;
}

//向第pos位置插入元素node
int DLinkList_Insert(DLinkList *list, DLinkListNode *node, int pos)
{
    int ret = 0, i = 0;
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *Current = NULL;
    DLinkListNode *Next = NULL;
    if (list == NULL || node == NULL || pos < 0)
    {
        ret = -1;
        printf("func DLinkList_Insert() (list == NULL || node == NULL || pos < 0) err:%d", ret);
        return ret;
    }

    if (pos > tlist->length)
    {
        ret = -2;
        printf("func DLinkList_Insert() (pos > tlist->length) err:%d\n", ret);
        return ret;
    }
    Current = (DLinkListNode *)tlist;

    for (i = 0; (i < pos) && (Current->next != NULL); i++)
    {
        Current = Current->next;
    }

    Next = Current->next;
    Current->next = node;  //1
    node->next = Next;     //2

    if (Next != NULL)
    {
        Next->pre = node;  //3
    }
    node->pre = Current;   //4

    if(tlist->length==0)
    { 
        tlist->slider = node;//当链表插入第一个元素处理游标
    }
    //若在0位置插入,需要特殊处理新节点next前pre指向NULL
    if (Current == (DLinkListNode *)tlist)
    {
        node->pre = NULL;
    }
    tlist->length++;

    return ret;
}

//获取第pos位置的元素
DLinkListNode *DLinkList_Get(DLinkList *list, int pos)
{
    int i = 0;
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *Current = NULL;
    DLinkListNode *ret = NULL;

    if (list == NULL || pos < 0)
    {
        printf("func DLinkList_Get() (list == NULL || pos < 0) err\n");
        return NULL;
    }
    if (pos > tlist->length)
    {
        printf("func DLinkList_Get() (pos > tlist->length) err\n");
        return  NULL;
    }
    Current = (DLinkListNode *)tlist;
    for (i = 0; (i < pos) && (Current->next != NULL); i++)
    {
        Current = Current->next;
    }
    ret = Current->next;

    return ret;
}

//删除第pos位置的元素
DLinkListNode *DLinkList_Delete(DLinkList *list, int pos)
{
    int i = 0;
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *Current = NULL;
    DLinkListNode *Next = NULL;
    DLinkListNode *ret = NULL;

    if (list == NULL || pos < 0)
    {
        printf("func DLinkList_Delete() (list == NULL || pos < 0) err\n");
        return NULL;
    }

    if (pos > tlist->length)
    {
        printf("func DLinkList_Deletee() (pos > tlist->length) err\n");
        return NULL;
    }
    Current = (DLinkListNode *)tlist;
    for (i = 0; (i < pos) && (Current->next != NULL); i++)
    {
        Current = Current->next;
    }
    ret = Current->next;
    Next = ret->next;               
    Current->next = Next;           //1

    if (Next != NULL)
    {
        Next->pre = Current;
        if (Current == (DLinkListNode *)tlist)
        {
            Next->pre = NULL;
        }
    }

    if (tlist->slider == ret)
    {
        tlist->slider = Next;
    }
    tlist->length--;

    return ret;
}

//获取当前游标的元素
DLinkListNode *DLinkList_Current(DLinkList *list)
{
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;
    if (list == NULL)
    {
        printf("func DLinkList_Current() (list == NULL) err\n");
        return NULL;
    }
    ret = tlist->slider;

    return ret;
}

//将游标重置指向链表的第一个位置元素
DLinkListNode *DLinkList_Rset(DLinkList *list)
{
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;
    if (list == NULL)
    {
        printf("func DLinkList_Rset() (list == NULL) err\n");
        return NULL;
    }
    tlist->slider = tlist->header.next;
    ret = tlist->slider;

    return ret;
}

//将游标移动指向到链表下一个位置元素
DLinkListNode *DLinkList_Next(DLinkList *list)
{
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;
    if (list == NULL)
    {
        printf("func DLinkList_Next() (list == NULL) err\n");
        return NULL;
    }
    ret = tlist->slider;
    tlist->slider = ret->next;

    return ret;
}

//将游标移动指向到链表上一个位置元素
DLinkListNode *DLinkList_Pre(DLinkList *list)
{
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;
    if (list == NULL)
    {
        printf("func DLinkList_Pre() (list == NULL) err\n");
        return NULL;
    }
    ret = tlist->slider;
    tlist->slider = ret->pre;

    return ret;

}

//直接删除指定链表中的某个元素
DLinkListNode *DLinkList_DeleteNode(DLinkList *list, DLinkListNode *node)
{
    int i = 0;
    TDLinkList *tlist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;
    DLinkListNode *Current = NULL;
    if (list == NULL || node)
    {
        printf("func DLinkList_DeleteNode() (list == NULL || node) err\n");
        return NULL;
    }

    Current = (DLinkListNode *)tlist;
    for (i = 0; i < tlist->length; i++)
    {
        if (Current->next == node)
        {
            ret = Current->next;
            break;
        }
    }
    if (ret != NULL)
    {
        DLinkList_Delete(tlist, i);
    }
    if (ret == tlist->slider)
    {
        tlist->slider = ret->next;
    }

    return ret;
}

双向链表集成测试框架

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "DLinkList.h"

typedef struct Value
{
    DLinkListNode node;
    int v;
}Value;

void main()
{
    int i = 0, ret = 0;
    Value v1, v2, v3, v4, v5;
    Value *tmp = NULL;

    DLinkList *list = DLinkList_Create();
    if (list == NULL)
    {
        printf("func DLinkList_Create()(list == NULL) err\n");
        return;
    }

    v1.v = 1;
    v2.v = 2;
    v3.v = 3;
    v4.v = 4;
    v5.v = 5;

    ret = DLinkList_Insert(list, (DLinkListNode *)&v1, DLinkList_Length(list));
    if (ret != 0)
    {
        printf("func DLinkList_Insert() (ret != 0) err:%d\n", ret);
        return;
    }

    ret = DLinkList_Insert(list, (DLinkListNode *)&v2, DLinkList_Length(list));
    if (ret != 0)
    {
        printf("func DLinkList_Insert() (ret != 0) err:%d\n", ret);
        return;
    }

    ret = DLinkList_Insert(list, (DLinkListNode *)&v3, DLinkList_Length(list));
    if (ret != 0)
    {
        printf("func DLinkList_Insert() (ret != 0) err:%d\n", ret);
        return;
    }

    ret = DLinkList_Insert(list, (DLinkListNode *)&v4, DLinkList_Length(list));
    if (ret != 0)
    {
        printf("func DLinkList_Insert() (ret != 0) err:%d\n", ret);
        return;
    }

    ret = DLinkList_Insert(list, (DLinkListNode *)&v5, DLinkList_Length(list));
    if (ret != 0)
    {
        printf("func DLinkList_Insert() (ret != 0) err:%d\n", ret);
        return;
    }

    printf("Get Elements:\n");
    for (i = 0; i < DLinkList_Length(list); i++)
    {
        tmp = (Value *)DLinkList_Get(list, i);
        printf("tmp->v:%d\n", tmp->v);
    }
    printf("\n");
    printf("\n");


    DLinkList_Delete(list, DLinkList_Length(list) - 1); //删除最后一个元素
    DLinkList_Delete(list, 0);                           //删除第一个元素

    printf("Delete first element and last element:\n");
    for (i = 0; i < DLinkList_Length(list); i++)
    {
        tmp = (Value *)DLinkList_Next(list);
        printf("tmp->v:%d\n", tmp->v);
    }

    printf("\n");
    DLinkList_Rset(list);   //游标重置
    DLinkList_Next(list);   //游标后移一个  3

    printf("reset slider,and move slider to next: \n");
    tmp = (Value *)DLinkList_Current(list);
    printf("tmp->v:%d\n", tmp->v);


    DLinkList_Pre(list);     //游标前移一个 2
    printf("mov slider to pre:\n");
    tmp = (Value *)DLinkList_Current(list);
    printf("tmp->v:%d\n", tmp->v);

    printf("Length:%d\n", DLinkList_Length(list));  

    DLinkList_Destroy(list);

    system("pause");
    return;
}

结果截图
线性表(List)---链式存储结构(双向链表)