首页 > 代码库 > 线性表之双向链表

线性表之双向链表

一,双向链表的基础知识

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);}

 

线性表之双向链表