zoukankan      html  css  js  c++  java
  • 线性表之双向链表

    一,双向链表的基础知识

    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
    ");
            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
    ");
            return NULL;
        }
        if (length(list) == 0)
        {
            printf("链表长度为0,删除失败
    ");
            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("未找到该元素
    ");
            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("##############基本遍历##############
    ");
        for (int i = 0; i < length(list); i++)
        {
            Student * stu = (Student *)get(list,i);
            printf("name = %s,age = %d
    ", stu->name, stu->age);
        }
    
        /* 删除 */
        del(list, 0);
        printf("##############删除0号位置后遍历##############
    ");
        for (int i = 0; i < length(list); i++)
        {
            Student * stu = (Student *)get(list, i);
            printf("name = %s,age = %d
    ", stu->name, stu->age);
        }
        /* 删除节点 */
        delNode(list,&s2);
        printf("##############删除s2后遍历##############
    ");
        for (int i = 0; i < length(list); i++)
        {
            Student * stu = (Student *)get(list, i);
            printf("name = %s,age = %d
    ", stu->name, stu->age);
        }
    
        /* 重置游标 */
        resetSlider(list);
        Student * ss1 = (Student *)current(list);
        printf("##############重置游标##############
    ");
        printf("name = %s,age = %d
    ", ss1->name, ss1->age);
        /* 游标下移 */
        next(list);
        Student * ss2 = (Student *)current(list);
        printf("##############游标下移##############
    ");
        printf("name = %s,age = %d
    ", ss2->name, ss2->age);
    
        next(list);
        Student * ss3 = (Student *)current(list);
        printf("##############游标下移##############
    ");
        printf("name = %s,age = %d
    ", ss3->name, ss3->age);
    
        /* 游标上移 */
        prev(list);
        ss2 = (Student *)current(list);
        printf("##############游标上移##############
    ");
        printf("name = %s,age = %d
    ", ss2->name, ss2->age);
    }
  • 相关阅读:
    (转载)你好,C++(21)只要天还没黑,就一直在工地干活-4.3.1 while循环:只要…就一直…
    (转载)你好,C++(20).4.2.2 表达并列条件选择的switch语句:如果……如果……如果……
    (转载)你好,C++(19)“老师,我这次四级考试过了没有?”——4.2 条件选择语句
    (转载)你好,C++(18) 到底要不要买这个西瓜?4.1.6 操作符之间的优先顺序
    (转载)你好,C++(17)0.1*10不等于1.0——4.1.4 关系操作符4.1.5 逻辑操作符
    (转载)你好,C++(16)用表达式表达我们的设计意图——4.1 用操作符对数据进行运算
    (转载)你好,C++(15)四两拨千斤——3.9 指向内存位置的指针
    (转载)你好,C++(14)如何描述“一个名叫陈良乔,年龄33岁,身高173厘米,体重61.5千克的男人”——3.8 用结构体类型描述复杂的事物
    (转载)你好,C++(13)这道单选题的答案是A、B、C还是D?3.7 枚举类型
    (转载)你好,C++(12)如何管理多个类型相同性质相同的数据?3.6 数组
  • 原文地址:https://www.cnblogs.com/metalsteel/p/6260848.html
Copyright © 2011-2022 走看看