双链表:结构体定义、创建、清除
双链表:结构体定义、创建、清除
一、结构体定义
(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;
}
运行结果: