线性表之双向链表

Posted 王刚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性表之双向链表相关的知识,希望对你有一定的参考价值。

一,双向链表的基础知识

1.双向链表的概念

  双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表的每个结点中都有两个指针域,一个指向其前驱结点,一个指向其后继结点。

2.双向链表实现的难点

  • 每一个数据元素有两个指针域,一个指向其前驱结点,一个指向其后继结点。
  • 第一个结点的前驱为NULL,最后一个节点的后继为NULL。

二,双向链表的实现

1.双向链表的基本功能(DoubleLinkList.h)

# ifndef DOUBLE_LINK_LIST
# define DOUBLE_LINK_LIST

/* 业务节点 */
typedef void Node;

/* 链表节点(被包含) */
typedef struct DoubleNode
{
    struct DoubleNode * prev;
    struct DoubleNode * next;
}DoubleNode;

/* 双向链表 */
typedef struct DoubleLinkList
{
    Node * ptr;
    DoubleNode  header;
    DoubleNode  slider;
    int length;
}DoubleLinkList;

/* 创建链表 */
DoubleLinkList * createList();

/* 清空链表 */
void clear(DoubleLinkList * list);

/* 销毁链表 */
void destory(DoubleLinkList * list);

/* 链表长度 */
int length(DoubleLinkList * list);

/* 链表是否为空 */
int empty(DoubleLinkList * list);

/* 插入链表 */
void insert(DoubleLinkList * list, int pos, Node * node);

/* 删除链表 */
Node * del(DoubleLinkList * list, int pos);

/* 删除某个元素 */
Node * delNode(DoubleLinkList * list, Node * node);

/* 获取链表 */
Node * get(DoubleLinkList * list, int pos);

/* 重置游标 */
void resetSlider(DoubleLinkList * list);

/* 游标下移 */
Node * next(DoubleLinkList * list);

/* 游标上移 */
Node * prev(DoubleLinkList * list);

/* 获取当前游标的结点 */
Node * current(DoubleLinkList * list);

# endif

 

2.双向链表基本功能的实现(DoubleLinkList.c)

# include<stdio.h>
# include<stdlib.h>
# include"DoubleLinkList.h"

/* 创建链表 */
DoubleLinkList * createList()
{
    DoubleLinkList * list = (DoubleLinkList *)malloc(sizeof(DoubleLinkList));

    /* 初始化头指针 */
    list->ptr = &(list->header);
    /* 初始化头结点 */
    list->header.next = NULL;
    list->header.prev = NULL;
    /* 初始化游标 */
    list->slider.next = NULL;
    /* 初始化链表长度 */
    list->length = 0;

    return list;
}

/* 清空链表 */
void clear(DoubleLinkList * list)
{
    /* 置空头结点 */
    list->header.next = NULL;
    list->header.prev = NULL;
    /* 置空游标 */
    list->slider.next = NULL;
    /* 置空链表长度 */
    list->length = 0;
}

/* 销毁链表 */
void destory(DoubleLinkList * list)
{
    if (list != NULL)
    {
        free(list);
        list = NULL;
    }
}

/* 链表长度 */
int length(DoubleLinkList * list)
{
    return list->length;
}

/* 链表是否为空 */
int empty(DoubleLinkList * list)
{
    if (list->length <= 0)
    {
        return 1;
    }
    else {
        return 0;
    }
}

/* 插入链表 */
void insert(DoubleLinkList * list, int pos, Node * node)
{
    if (list == NULL)
    {
        printf("链表为NULL\n");
        return;
    }
    /* 判断插入位置合法性 */
    pos = pos < 0 ? 0 : pos;
    pos = pos > length(list) ? length(list) : pos;
    /* 将业务结点转换为链表结点 */
    DoubleNode * _node = (DoubleNode *)node;
    /* 判断是否是第一次插入 */
    if (length(list) == 0)
    {
        list->header.next = _node;
        _node->prev = NULL;
        _node->next = NULL;
        list->length++;
        return;
    }
    /* 判断是否是插入头部 */
    if (pos == 0)
    {
        list->header.next->prev = _node;
        _node->next = list->header.next;
        list->header.next = _node;
        _node->prev = NULL;
    }
    else {
        DoubleNode * posNode = list->header.next;
        DoubleNode * previous = posNode;
        for (int i = 0; i < pos; i++)
        {
            previous = posNode;
            posNode = posNode->next;
        }
        previous->next = _node;
        _node->prev = previous;
        posNode->prev = _node;
        _node->next = posNode;
    }
    list->length++;
}

/* 删除链表 */
Node * del(DoubleLinkList * list, int pos)
{
    if (list == NULL)
    {
        printf("链表为NULL\n");
        return NULL;
    }
    if (length(list) == 0)
    {
        printf("链表长度为0,删除失败\n");
        return NULL;
    }
    /* 判断删除位置合法性 */
    pos = pos < 0 ? 0 : pos;
    pos = pos > length(list) ? length(list) : pos;
    /* 定义删除的返回结点 */
    DoubleNode * result = NULL;
    /* 判断是否删除第一个 */
    if (pos == 0)
    {
        result = list->header.next;
        list->header.next = list->header.next->next;
        list->header.next->prev = NULL;
    }
    else {
        DoubleNode * posNode = list->header.next;
        DoubleNode * previous = posNode;
        for (int i = 0; i < pos; i++)
        {
            previous = posNode;
            posNode = posNode->next;
        }
        result = posNode;
        previous->next = posNode->next;
        posNode->next->prev = previous;
    }
    list->length--;
    return result;
}

/* 删除某个元素 */
Node * delNode(DoubleLinkList * list, Node * node)
{
    /* 找出该元素位置 */
    int pos = -1;
    /* 遍历寻找 */
    for (int i = 0; i < length(list); i++)
    {
        Node * tmp = get(list, i);
        if (tmp == node)
        {
            pos = i;
        }
    }
    /* 如果未找到退出 */
    if (pos == -1)
    {
        printf("未找到该元素\n");
        return NULL;
    }
    /* 找到后删除 */
    Node * result = del(list, pos);

    return result;
}

/* 获取链表 */
Node * get(DoubleLinkList * list, int pos)
{
    DoubleNode * posNode = list->header.next;
    for (int i = 0; i < pos; i++)
    {
        posNode = posNode->next;
    }
    return posNode;
}

/* 重置游标 */
void resetSlider(DoubleLinkList * list)
{
    list->slider.next = list->header.next;
}

/* 游标下移 */
Node * next(DoubleLinkList * list)
{
    if (list->slider.next->next != NULL)
    {
        DoubleNode * result = list->slider.next;
        list->slider.next = list->slider.next->next;
        return result;
    }
    return NULL;
}

/* 游标上移 */
Node * prev(DoubleLinkList * list)
{
    if (list->slider.next->prev != NULL)
    {
        DoubleNode * result = list->slider.next;
        list->slider.next = list->slider.next->prev;
        return result;
    }
    return NULL;
}

/* 获取当前游标的结点 */
Node * current(DoubleLinkList * list)
{
    return list->slider.next;
}

 

3.双向链表的测试

# define _CRT_SECURE_NO_WARNINGS
# include<stdio.h>
# include<string.h>
# include"DoubleLinkList.h"

typedef struct Student
{
    DoubleNode next;
    char name[64];
    int age;
}Student;

int main()
{
    Student s1;
    strcpy(s1.name, "刘备");
    s1.age = 56;

    Student s2;
    strcpy(s2.name, "关羽");
    s2.age = 40;

    Student s3;
    strcpy(s3.name, "张飞");
    s3.age = 38;

    /* 创建双向链表 */
    DoubleLinkList * list = createList();

    /* 插入数据 */
    insert(list, 0, &s1);
    insert(list, 0, &s2);
    insert(list, 0, &s3);

    /* 遍历 */
    printf("##############基本遍历##############\n");
    for (int i = 0; i < length(list); i++)
    {
        Student * stu = (Student *)get(list,i);
        printf("name = %s,age = %d\n", stu->name, stu->age);
    }

    /* 删除 */
    del(list, 0);
    printf("##############删除0号位置后遍历##############\n");
    for (int i = 0; i < length(list); i++)
    {
        Student * stu = (Student *)get(list, i);
        printf("name = %s,age = %d\n", stu->name, stu->age);
    }
    /* 删除节点 */
    delNode(list,&s2);
    printf("##############删除s2后遍历##############\n");
    for (int i = 0; i < length(list); i++)
    {
        Student * stu = (Student *)get(list, i);
        printf("name = %s,age = %d\n", stu->name, stu->age);
    }

    /* 重置游标 */
    resetSlider(list);
    Student * ss1 = (Student *)current(list);
    printf("##############重置游标##############\n");
    printf("name = %s,age = %d\n", ss1->name, ss1->age);
    /* 游标下移 */
    next(list);
    Student * ss2 = (Student *)current(list);
    printf("##############游标下移##############\n");
    printf("name = %s,age = %d\n", ss2->name, ss2->age);

    next(list);
    Student * ss3 = (Student *)current(list);
    printf("##############游标下移##############\n");
    printf("name = %s,age = %d\n", ss3->name, ss3->age);

    /* 游标上移 */
    prev(list);
    ss2 = (Student *)current(list);
    printf("##############游标上移##############\n");
    printf("name = %s,age = %d\n", ss2->name, ss2->age);
}

 

以上是关于线性表之双向链表的主要内容,如果未能解决你的问题,请参考以下文章

Java数据结构线性表之链表

Java数据结构线性表之链表

线性表之双向链表

数据结构线性表之双向带头循环链表

数据结构学习笔记二线性表之链表篇(双向链表)

线性链表之顺序表