双链表:结构体定义、创建、清除

双链表:结构体定义、创建、清除

一、结构体定义

(1)双链表与单链表的区别在于,多了一个前向指针,结构体声明如下。
(2)该声明同时利用typedef重定义了结构体类型,将struct DoubleLinkNode类型重定义为DOUBLE_LINKED_NODE类型,后续可以直接用其定义变量;
(3)由于在结构体内需递归使用结构体定义前驱和后继指针,但是在定义指针时DOUBLE_LINKEND_NODE还未生效,所以此时只能使用struct DoubleLinkNode * 来声明指针。

// 双链表结构体:链表内的每个节点有两个链域,一个指向前驱,一个指向后继 
typedef struct DoubleLinkNode {
    void *data;
    // 指向前一个节点的指针
    struct DoubleLinkNode* pre;
    // 指向后一个节点的指针
    struct DoubleLinkNode* next;
} DOUBLE_LINKED_NODE;

二、创建双链表

1、说明:输入数组指针,数组长度和数组元素大小;返回创建好的链表头指针
2、步骤:设置头结点->逐个添加数组其他元素
3、源码:


// 创建双链表:输入数组指针,数组长度,数组元素大小;返回创建好的链表头指针
DOUBLE_LINKED_NODE* createDoubleLinkedList(void *array, int len, int size)
{
    DOUBLE_LINKED_NODE *newNode = NULL;
    DOUBLE_LINKED_NODE *tailNode = NULL;
    // 设置头结点,共四步:申请结构体内存,申请数据区内存,数据区赋值,指针赋值
    DOUBLE_LINKED_NODE *headNode = (DOUBLE_LINKED_NODE*)malloc(sizeof(DOUBLE_LINKED_NODE));
    headNode->data = (void*)malloc(size);
    memcpy(headNode->data, array, size);
    headNode->pre = NULL;
    headNode->next = NULL;
    // 设置尾节点
    tailNode = headNode;

    // 逐个加点添加,后移尾节点,
    for (int i = 1; i < len; i++) {
        // 添加新节点:参考头结点的四个步骤
        newNode = (DOUBLE_LINKED_NODE *)malloc(sizeof(DOUBLE_LINKED_NODE));
        newNode->data = (void*)malloc(size);
        memcpy(newNode->data, array + i * size, size);
        // 双链表的精髓在于指针的处理:
        // tailNode->next, 原值为NULL,表示链表结束;现在需要将指正指向nextNode
        tailNode->next = newNode;
        // newNode接在tailNode后面,所以将newNode->pre指向tailNode
        newNode->pre = tailNode;
        // newNode此时实际上是尾节点,需要将其newNode->next指向空
        newNode->next = NULL;
        // 更新尾节点的指针
        tailNode = newNode;
    }

    return headNode;
}

三、清除双链表

// 清理双链表,释放空间(从当前节点开始,释放后续的所有链表空间,当前节点之前的空间不释放)
int clearDoubleLinkedList(DOUBLE_LINKED_NODE *doubleLinkNode)
{
    // 清理数据区
    if (doubleLinkNode->data != NULL) {
        free (doubleLinkNode->data);
        // 内存释放后,将指针赋空
        doubleLinkNode->data = NULL;
    }
    // 使用递归方法清理,分离本节点与后续节点,不释放之前的节点
    if (doubleLinkNode->pre != NULL) {
        // 该指针原本指向doubleLinkNode,现将其分离
        doubleLinkNode->pre->next = NULL;
    }
    doubleLinkNode->pre = NULL;
    if (doubleLinkNode->next == NULL) {
        // 链表释放完毕,无后继
        return 0;
    }
    // 还存在后续节点时,递归处理,处理下一个节点,直到无后继
    clearDoubleLinkedList(doubleLinkNode->next);
    // 释放当前节点空间: 上一层的递归处理完成后,需要释放本层的节点空间
    free(doubleLinkNode->next);
    doubleLinkNode->next = NULL;

    return 0;
}

四、测试

测试步骤:先根据数组数据创建一个链表,输出内容后,再删除,测试代码如下:

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

#define LIST_LEN 8

// 结构体定义
// 创建双链表函数实现
// 删除双链表函数实现

static int printfDoubleList(char *info, DOUBLE_LINKED_NODE *node)
{
    DOUBLE_LINKED_NODE *nodeTenp = node;
    printf("%s", info);
    while (nodeTenp != NULL && nodeTenp->data != NULL) {
        printf("%d ", *(int*)(nodeTenp->data));
        nodeTenp = nodeTenp->next;
    }
    printf("\n");
    return 0;
}

int main(void)
{
    int array[LIST_LEN] = {0, 1, 2, 3, 9, 8, 7, 6};
    DOUBLE_LINKED_NODE *temp, *printfTemp;
    // 创建双链表
    temp = createDoubleLinkedList(array, LIST_LEN, sizeof(int));
    printfDoubleList("createDoubleLinkedList:", temp);
    // 清空双链表
    clearDoubleLinkedList(temp->next->next);
    printfDoubleList("clearDoubleLinkedList:", temp);

    while(1);
    return 0;
}

运行结果:

posted @ 2021-01-19 00:49  Pangolin2  阅读(734)  评论(0编辑  收藏  举报