C语言 实现一个双链表

一、 概述

链表是一种常见的数据结构了,我们希望实现类似如下的双向链表(图片来源网络):
这里写图片描述

如下定义:

typedef struct DoubleLinkList
{
    DLNode* head;   // 链表头
    DLNode* back;  // 链表尾
    size_t size;    //链表包含的元素的个数 typedef unsigned int   size_t;  
}DLlist;  // 双链表 

每个元素或节点如下(图片来源网络):
这里写图片描述

如下定义:

typedef struct DoubleLinkListNode
{
    struct DoubleLinkListNode* pPre;  // 前一个节点指针
    struct DoubleLinkListNode* pNext; // 后一个节点指针
    _TYPE value;
}DLNode;  // 节点

结构体不熟悉的可以参考:C语言 结构体与共用体


二、实现

1 头文件

编写如下doublelinklist.h头文件

#pragma once 

#define _ASC 1  // 升序排序
#define _DESC 0  // 降序排序
typedef int _TYPE;  // 数据类型

typedef struct DoubleLinkListNode
{
    struct DoubleLinkListNode* pPre;  // 前一个节点指针
    struct DoubleLinkListNode* pNext; // 后一个节点指针
    _TYPE value;
}DLNode;  // 节点

typedef struct DoubleLinkList
{
    DLNode* head;   // 链表头
    DLNode* back;  // 链表尾
    size_t size;    //链表包含的元素的个数 typedef unsigned int   size_t;  
}DLlist;  // 双链表 

// 对一个新链表进行初始化
void init(DLlist* pList);

// 快速创建一个空的双链表
DLlist* _createList(); 

// 使用可变参数来创建一个链表
DLlist* _createListWithValues(int length, ...);

// 使用数组来创建一个链表
DLlist* _createListWithArrayValues(_TYPE array[], int length);

// 插入到头部,返回1插入成功
int addToHead(DLlist* pList, _TYPE value);

// 插入到尾部,返回1插入成功
int addToBack(DLlist* pList, _TYPE value);

// 将一维数组的值添加到链表头部,返回1插入成功
int addToHeadWithArrayValues(DLlist* pList, _TYPE array[], int length);

// 将一维数组的值添加到链表尾部,返回1插入成功
int addToBackWithArrayValues(DLlist* pList,_TYPE array[], int length);

// 插入到指定元素的后面,返回1插入成功
int insertAfter(DLlist* pList, _TYPE curValue, _TYPE newValue);

// 插入到指定元素的后面,返回1插入成功,改进版
int insertAfter2(DLlist* pList, _TYPE curValue, _TYPE newValue);

// 插入到指定元素的前面,返回1插入成功
int insertBefore(DLlist* pList, _TYPE curValue, _TYPE newValue);

// 插入到指定元素的前面,返回1插入成功,改进版
int insertBefore2(DLlist* pList, _TYPE curValue, _TYPE newValue);

// 删除第一个节点,并返回它
DLNode* removeFirst(DLlist* pList);

// 删除最后一个节点,并返回它
DLNode* removeLast(DLlist* pList);

// 正向显示所有
void showAll(DLlist* pList);

// 使用递归正向显示所有
void showAllWithRecursion(DLNode* head);

// 反向显示所有
void showAllReverse(DLlist* pList); 

// 使用递归反向显示所有
void showAllReverseWithRecursion(DLNode* back);

// 删除指定元素,返回1删除成功
int deleteNode(DLlist* pList, _TYPE value);

// 删除指定元素,返回1删除成功,deleteNode改进版
int deleteNode2(DLlist* pList, _TYPE value);

// 删除一个范围的元素,从fromValue的节点开始删除,删除count个
int deleteRange(DLlist* pList, _TYPE fromValue,int count);

// 检查是否为空
int checkNull(void* p);

// 修改指定的值,返回1修改成功
int modify(DLlist* pList, _TYPE oldValue, _TYPE newValue);

// 释放所有元素,清空链表,返回1则成功
int freeAll(DLlist* pList);

// 从第一个匹配元素开始释放,返回1删除成功
int freeFrom(DLlist* pList, _TYPE value);

// 通过值找到指定匹配的第一个节点
DLNode* findByValue(DLlist* pList, _TYPE value);

// 将一个链表插入当前链表的尾部
int addListToBack(DLlist* pList, DLlist* addingList);

// 获取指定值的节点在链表中的深度
int getDepth(DLlist* pList, _TYPE value);

// 是否为空,返回1则为空
int isEmpty(DLlist* pList);  

// 对链表值进行排序,asc为0则降序序排,否则升序。可以使用_ASC(升序) , _DESC(降序)
void sort(DLlist* pList,int asc);

2 函数实现

在DoubleLinkList.c中实现。下面将函数分个显示

void init (DLlist* pList);

用于给通过DoubleLinkList创建的新链表进行初始化

void init(DLlist* pList)
{
    pList->head = pList->back = NULL;
    pList->size = 0;
}

DLlist* _createList();

快速创建一个双链表

DLlist* _createList()
{
    DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
    pList->head = pList->back = NULL;
    pList->size = 0;
    return pList;
}

DLlist* _createListWithValues (int length, …)

使用可变参数来创建一个链表,需要声明头文件#include<stdarg.h>
DLlist* _createListWithValues(int length, ...)
{
    DLlist* pList = _createList();

    va_list ap; // 参数指针
    va_start(ap, length); // 第一个元素
    for (int i = 0; i < length; i++)
    {
        addToBack(pList,va_arg(ap, _TYPE)); // 返回对应类型的数据,并添加到链表
    }
    va_end(ap);

    return pList;
}

DLlist* _createListWithArrayValues (_TYPE array[], int length)

使用数组的元素来创建一个链表,length表示要添加到链表的个数


DLlist* _createListWithArrayValues(_TYPE array[], int length)
{
    if (checkNull(array)|| 0==length)
    {
        return NULL;
    }

    DLlist* pList =  _createList();
    if (checkNull(pList))
    {
        return NULL;
    }

    if (addToBackWithArrayValues(pList, array, length))
    {
        return pList;
    }

    return NULL;
}

int addToHead (DLlist* pList, _TYPE value);

插入双链表的头部,返回1则表示插入成功

int addToHead(DLlist* pList, _TYPE value)
{
    if (checkNull(pList))
    {
        return 0;
    }

    DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
    if (checkNull(newNode))
    {
        return 0;   // 创建新节点失败,则返回
    }
    newNode->pNext = newNode->pPre = NULL;
    newNode->value = value;

    if (pList->head==NULL)  // 若头节点为空,则新节点置为头节点
    {
        pList->head = newNode;
        pList->back = newNode;
        pList->size++;
    }
    else    // 添加到头部
    {
        newNode->pNext = pList->head;
        pList->head->pPre = newNode;
        pList->head = newNode;  // 将链表的头部设为新节点  
        pList->size++;
    }
    return 1;
}

int addToBack (DLlist* pList, _TYPE value);

插入到双链表的尾部,返回1插入成功

int addToBack(DLlist* pList, _TYPE value)
{
    if (checkNull(pList))
    {
        return 0;
    }
    DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
    if (checkNull(newNode))
    {
        return 0;   // 创建新节点失败,则返回
    }
    newNode->pNext = newNode->pPre = NULL;
    newNode->value = value;
    if (NULL == pList->head)  // 若头节点为空,则新节点置为头节点
    {
        pList->head = newNode;
        pList->back = newNode;
        pList->head->pNext = pList->back->pNext = NULL;
        pList->size++;
    }
    else if (pList->size == 1)  // 只有一个元素,头尾都指向它,链接好头部与下一个节点
    {
        newNode->pPre = pList->head;
        pList->head->pNext = newNode;
        pList->back = newNode;
        pList->size++;
    }
    else  // 添加到尾部
    {
        newNode->pPre = pList->back;
        pList->back->pNext = newNode;
        pList->back = newNode;
        pList->size++;
    }

    return 1;
}

int addToHeadWithArrayValues (DLlist* pList, _TYPE array[], int length)

将一维数组的值添加到链表头部,返回1插入成功

int addToHeadWithArrayValues (DLlist* pList, _TYPE array[], int length)
    {
        if (checkNull(pList) || checkNull(array) || length == 0)
        {
            return 0;
        }

        for (int i = 0; i < length; i++)
        {
            if (!addToHead(pList, array[i]))
            {
                return 0;
            }
        }

        return 1;
    }

int addToBackWithArrayValues (DLlist* pList, _TYPE array[], int length)

将一维数组的值添加到链表尾部,返回1插入成功

int addToBackWithArrayValues(DLlist* pList, _TYPE array[], int length)
    {
        if (checkNull(pList) || checkNull(array) || length == 0)
        {
            return 0;
        }

        for (int i = 0; i < length; i++)
        {
            if (!addToBack(pList, array[i]))
            {
                return 0;
            }
        }

        return 1;
    }

int insertAfter (DLlist* pList, _TYPE curValue, _TYPE newValue);

插入到指定值curValue的节点元素的后面,返回1则插入成功

int insertAfter(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:插入指定节点后面失败,空链表\n");
        return 0;
    }

    DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
    if (checkNull(newNode))
    {
        return 0;   // 创建新节点失败,则返回
    }
    newNode->pNext = newNode->pPre = NULL;
    newNode->value = newValue;

    if (pList->head->value==curValue)  // 头节点满足
    {
        DLNode* next = pList->head->pNext;
        next->pPre = newNode;
        newNode->pNext = next;
        newNode->pPre = pList->head;
        pList->head->pNext = newNode;
        pList->size++;
        return 1;
    }
    else if (pList->back->value == curValue)  // 尾节点满足,防止要遍历一遍,浪费时间
    {
        pList->back->pNext = newNode;
        newNode->pPre = pList->back->pNext;
        pList->back;
        pList->size++;
        return 1;
    }
    else  // 其他
    {
        DLNode* p = pList->head->pNext;
        while (p)
        {
            if (p->value==curValue)
            {
                DLNode* next = p->pNext;
                next->pPre = newNode;
                newNode->pNext = next;
                newNode->pPre = p;
                p->pNext = newNode;
                pList->size++;
                return 1;
            }
            p = p->pNext;
        }
    }

    return 0;
}  

int insertAfter2 (DLlist* pList, _TYPE curValue, _TYPE newValue);

插入到指定值curValue的节点元素的后面,返回1插入成功,insertAfter改进版

int insertAfter2(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:插入指定节点后面失败,空链表\n");
        return 0;
    }
    DLNode* curNode = findByValue(pList, curValue); // 查找指定节点
    if (checkNull(pList))
    {
        printf("\n插入失败,目标节点value=%d不存在\n", curNode);
        return 0;
    }

    DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
    if (checkNull(newNode))
    {
        return 0;
    }
    newNode->pNext = newNode->pPre = NULL;
    newNode->value = newValue;
    if (curNode==pList->back)
    {
        pList->back->pNext = newNode;
        newNode->pPre = pList->back;
        pList->back = newNode;
        pList->size++;
    }
    else
    {
        DLNode* nextNode = curNode->pNext;
        newNode->pPre = curNode;
        newNode->pNext = nextNode;
        curNode->pNext = newNode;
        nextNode->pPre = newNode;
        pList->size++;
    }

    return 1;
}

int insertBefore (DLlist* pList, _TYPE curValue, _TYPE newValue);

插入到指定值curValue的节点元素的前面,返回1则插入成功

int insertBefore(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:插入指定节点前面失败,空链表\n");
        return 0;
    }

    DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
    if (checkNull(newNode))
    {
        return 0;
    }
    newNode->pNext = newNode->pPre = NULL;
    newNode->value = newValue;
    if (curValue == pList->head->value)  // 头节点满足
    {
        newNode->pNext = pList->head;
        pList->head->pPre = newNode;
        pList->head = newNode;
        pList->size++;
        return 1;
    }
    else if(pList->back->value == curValue) // 尾节点满足
    {
        newNode->pNext = pList->back;
        newNode->pPre = pList->back->pPre;
        pList->back->pPre->pNext = newNode; // 改变尾节点前面一个节点的指向,到newNode  
        pList->back->pPre = newNode;// 添加到尾节点前面
        pList->size++;
        return 1;
    }
    else
    {
        DLNode* curNode = pList->head->pNext;
        while (curNode)
        {
            if (curNode->value == curValue)
            {
                DLNode* preNode =  curNode->pPre;
                newNode->pNext = curNode;
                newNode->pPre = preNode;
                curNode->pPre = newNode;   // 添加到当前结点前面
                preNode->pNext = newNode;
                pList->size++;
                return 1;
            }
            curNode = curNode->pNext;
        }
    }
    return 0;
}

int insertBefore2 (DLlist* pList, _TYPE curValue, _TYPE newValue);

插入到指定值curValue的节点元素的前面,返回1则插入成功,insertBefore改进版

int insertBefore2(DLlist* pList, _TYPE curValue, _TYPE newValue)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:插入指定节点后面失败,空链表\n");
        return 0;
    }

    DLNode* curNode = findByValue(pList, curValue); // 查找指定节点
    if (checkNull(pList))
    {
        printf("\n插入失败,目标节点value=%d不存在\n", curNode);
        return 0;
    }

    DLNode* newNode = (DLNode*)malloc(sizeof(DLNode));
    if (checkNull(newNode))
    {
        return 0;
    }
    newNode->pNext = newNode->pPre = NULL;
    newNode->value = newValue;

    if (curNode==pList->head)
    {
        newNode->pNext = pList->head;
        pList->head->pPre = newNode;
        pList->head = newNode;
        pList->size++;
    }
    else
    {

        DLNode* preNode = curNode->pPre;
        newNode->pNext = curNode;
        newNode->pPre = preNode;
        curNode->pPre = newNode;
        preNode->pNext = newNode;
        pList->size++;
    }
    return 1;
}

DLNode* removeFirst (DLlist* pList);

删除第一个节点,并返回它

DLNode* removeFirst(DLlist* pList)
{
    if (checkNull(pList))
    {
        return NULL;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return NULL;
    }
    if (pList->head->pNext==NULL)   // 只有head
    {
        DLNode* head = pList->head;
        pList->head = NULL;
        pList->size--;
        return head;
    }
    else
    {
        DLNode* head = pList->head;
        DLNode* next = head->pNext;
        head->pNext = NULL;
        next->pPre = NULL;
        pList->head = next;
        pList->size--;
        return head;
    }

    return NULL;
}

DLNode* removeLast (DLlist* pList);

删除最后一个节点,并返回它

DLNode* removeLast(DLlist* pList)
{
    if (checkNull(pList))
    {
        return NULL;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return NULL;
    }
    if (pList->back==pList->head)
    {
        return removeFirst(pList);
    }
    else
    {
        DLNode* back = pList->back;
        DLNode* preNode = back->pPre;
        back->pPre = NULL;
        preNode->pNext = NULL;
        pList->back = preNode;
        pList->size--;
        return back;
    }
    return NULL;
}

void showAll (DLlist* pList);

正向显示所有节点值

void showAll(DLlist* pList)
{
    if (checkNull(pList))
    {
        return;

    }
    else
    {
        if (isEmpty(pList))
        {
            printf("\nlog:showAll 空链表\n");
            return;
        }
        printf("\n[  ");
        DLNode* p = pList->head;
        while (p!=NULL)
        {
            printf("%d  ", p->value);
            p = p->pNext;  // 往后遍历
        }
        printf("]\n");
    }
}

void showAllWithRecursion (DLNode* head);

使用递归正向显示所有节点的值

void showAllWithRecursion(DLNode* head)
{
    static count = 0;

    if (NULL==head)
    {
        printf("]\n"); // 打印结束 ]
        count = 0;
        return;
    }
    else
    {
        if (count == 0)   // 打印起始 [
        {
            printf("\n[  ");
        }
        count++;
        printf("%d  ", head->value);
        showAllWithRecursion(head->pNext); // 递归调用,打印后面一个
    }
}

void showAllReverse (DLlist* pList);

反向显示所有节点的值

void showAllReverse(DLlist* pList)
{
    if (checkNull(pList))
    {
        return;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return 0;
    }
    printf("\n[  ");
    DLNode* p = pList->back;
    while (p!=NULL) 
    {
        printf("%d  ", p->value);
        p = p->pPre;  // 往前遍历
    }
    printf("]\n");
}

void showAllReverseWithRecursion (DLNode* back);

使用递归反向显示所有节点的值

void showAllReverseWithRecursion(DLNode* back)
{
    if (NULL ==back)
    {
        printf("\n");
        return;
    }
    else
    {
        printf("%d\t", back->value);
        showAllReverseWithRecursion(back->pPre); // 递归调用,打印前一个
    }
}

int deleteNode (DLlist* pList, _TYPE value);

删除第一个指定元素的节点,返回1则删除成功

int deleteNode(DLlist* pList, _TYPE value)
{

    if (checkNull(pList))
    {
        printf("\nlog:删除节点失败\n");
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:删除节点失败,空链表\n");
        return 0;
    }
    DLNode* findNode = findByValue(pList, value);
    if (checkNull(findNode))
    {
        printf("\nlog:要删除的节点不存在,value=%d\n", value);
        return 0;
    }
    if (value == pList->head->value)  // 头节点满足
    {
        if (pList->head->pNext==NULL)  // 只有head时
        {
            DLNode* curNode = pList->head;
            pList->head = pList->back = NULL;  // 删除所有节点后将head与back都赋值NULL
            free(curNode);
        }
        else
        {
            DLNode* curNode = pList->head;
            pList->head = curNode->pNext;   // 头节点后移
            free(curNode);

        }
        pList->size--;
        return 1;
    }
    else if (value == pList->back->value)   // 尾节点满足
    {
        DLNode* curNode = pList->back;
        pList->back = curNode->pPre;
        pList->back->pNext = NULL;
        free(curNode);
        pList->size--;
        return 1;
    }
    else
    {
        DLNode* curNode = pList->head->pNext;
        while (curNode!=NULL)       // 下面可以调用findByValue来查找指定节点
        {
            if (curNode->value==value)  // 删除满足条件的节点
            {
                DLNode* preNode = curNode->pPre;
                DLNode* nextNode = curNode->pNext;
                preNode->pNext = nextNode;
                nextNode->pPre = preNode;
                free(curNode);  // 释放内存
                pList->size--;
                return 1;
            }
            curNode = curNode->pNext;
        }
    }
    return 0;
}

int deleteNode2 (DLlist* pList, _TYPE value)

删除指定元素,返回1删除成功,deleteNode改进版

int deleteNode2(DLlist* pList, _TYPE value)
{
    if (checkNull(pList))
    {
        printf("\nlog:删除节点失败\n");
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:删除节点失败,空链表\n");
        return 0;
    }
    DLNode* findNode = findByValue(pList, value);
    if (checkNull(findNode))
    {
        printf("\nlog:要删除的节点不存在,value=%d\n", value);
        return 0;
    }
    if (findNode==pList->head)
    {
        DLNode* curNode = pList->head;
        pList->head = curNode->pNext;
        pList->head->pPre = NULL;
        free(curNode);
        pList->size--;
    }
    else
    {
        DLNode* preNode = findNode->pPre;
        DLNode* next = findNode->pNext;
        preNode->pNext = next;
        next->pPre = preNode;  // 上一个节点与下一个节点连接起来
        free(findNode);
        pList->size--;
    }
    return 0;
}

int deleteRange (DLlist* pList, _TYPE fromValue,int count);

删除一个范围的元素节点,从fromValue值的节点开始删除,删除count个。返回1表示删除成功

int deleteRange(DLlist* pList, _TYPE fromValue, int count)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return 0;
    }

    DLNode* curNode = findByValue(pList,fromValue);
    if (checkNull(curNode))
    {
        return 0;
    }

    int num = 0;
    if (curNode==pList->head)   // 如果是头节点
    {
        while (num < count && deleteNode(pList, pList->head->value))    // 从头部开始删除count个
        {
            ++num;
        }
        return 1;
    }
    else
    {
        DLNode* preNode = curNode->pPre;
        while (curNode)
        {
            if (num<count)
            {
                preNode->pNext = curNode->pNext;
                curNode->pPre = preNode;
                free(curNode);
                ++num;
            }
            else
            {
                break;
            }
            curNode = preNode->pNext;
        }
    }

    if (num == count || NULL == curNode) // 如果删除了指定数量或已经是尾节点下一个了
    {
        pList->size -= (num==count)?  count:  num;
        return 1;
    }
    return 0;
}

int checkNull (void* p);

检查指针是否为空

int checkNull(void* p)
{
    if (NULL == p)
    {
        printf("\nlog: null pointer\n");
        return 1;
    }
    return 0;
}

int modify (DLlist* pList, _TYPE oldValue, _TYPE newValue);

修改指定的值的节点,返回1表示修改成功

int modify(DLlist* pList, _TYPE oldValue, _TYPE newValue)
{
    if (checkNull(pList) )
    {
        return 0;
    }

    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return 0;
    }
    DLNode* curNode = pList->head;
    while (curNode)
    {
        if (curNode->value==oldValue)
        {
            curNode->value = newValue;
            return 1;
        }
        curNode = curNode->pNext;
    }

    return 0;
}

int freeAll (DLlist* pList);

释放所有元素,清空链表,返回1则成功

int freeAll(DLlist* pList)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return 0;
    }
    DLNode* curNode = pList->head->pNext;
    while (curNode)     // 循环删除头节点的下一个节点
    {
        pList->head->pNext = curNode->pNext;
        free(curNode);
        curNode = pList->head->pNext;
    }

    free(pList->head);  // 删除头节点
    pList->head = pList->back = NULL;
    pList->size = 0;
    return 1;
}

int freeFrom (DLlist* pList, _TYPE value);

从第一个匹配值的节点开始释放,截断并丢弃从指定值节点开始到结尾的链。返回1删除成功

int freeFrom(DLlist* pList, _TYPE value)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return 0;
    }

    DLNode* curNode = findByValue(pList, value);
    if (curNode==NULL)
    {
        printf("\nlog: 要删除value=%d的起始节点不存在\n",value);
        return 0;
    }
    if (curNode==pList->head)
    {
        return freeAll(pList);
    }
    else
    {
        DLNode* preNode = curNode->pPre;
        int depth = getDepth(pList, preNode->value);
        DLlist* dyingList = (DLlist*)malloc(sizeof(DLlist)); // 将要被删除的链表
        if (checkNull(dyingList))
        {
            return 0;
        }
        dyingList->head = curNode;
        freeAll(dyingList);  // 调用freeAll来删除
        free(dyingList);
        preNode->pNext = NULL;  // 将curNode的上一个节点的pNext置NULL
        pList->back = preNode;  // 重新设置尾节点
        pList->size = depth;
    }

    return 1;
}

DLNode* findByValue (DLlist* pList, _TYPE value);

通过值找到指定匹配的第一个节点

DLNode* findByValue(DLlist* pList, _TYPE value)
{
    if (checkNull(pList))
    {
        return 0;
    }
    if (isEmpty(pList))
    {
        printf("\nlog:空链表\n");
        return 0;
    }

    DLNode* curNode = pList->head;
    while (curNode)
    {
        if (curNode->value==value)
        {
            return curNode;
        }
        curNode = curNode->pNext;
    }
    return NULL;  // 没有找到还回空
}

int addListToBack (DLlist* pList, DLlist* addingList);

将一个链表插入当前链表的尾部

int addListToBack(DLlist* pList, DLlist* addingList)
{
    if (checkNull(pList)|| checkNull(addingList)||isEmpty(addingList))
    {
        return 0;
    }

    DLNode* curNode = addingList->head;
    while (curNode)
    {
        addToBack(pList, curNode->value);   // 添加到尾部
        curNode = curNode->pNext;
    }
    return 1;
}

int getDepth (DLlist* pList, _TYPE value);

获取指定值的节点在链表中的深度

int getDepth(DLlist* pList, _TYPE value)
{
    if (checkNull(pList))
    {
        return -1;
    }
    if (isEmpty(pList))
    {
        return 0;
    }
    DLNode* curNode = pList->head;
    int depth = 0;
    while (curNode)
    {
        depth++;
        if (curNode->value==value)
        {
            return depth;
        }
        curNode = curNode->pNext;
    }

    return -1;
}

int isEmpty (DLlist* pList);

判断链表是否为空,返回1则为空

int isEmpty(DLlist* pList)
{
    if (checkNull(pList))
    {
        return 1;
    }
    return pList->size == 0;
}

void sort (DLlist* pList, int asc)

使用选择排序法对链表值进行排序,asc为0则降序序排,否则升序。可以使用_ASC(升序) , _DESC(降序)

void sort(DLlist* pList, int asc)
{
    if (checkNull(pList) || isEmpty(pList))
    {
        return;
    }
    for (DLNode *pi = pList->head; pi->pNext!=NULL; pi = pi->pNext)
    {
        DLNode *pk = pi;
        for (DLNode *pj = pi->pNext; pj!= NULL; pj = pj->pNext)
        {
            if (asc && pk->value > pj->value)       // 排升序
            {
                pk = pj;
            }
            if (!asc && pk->value < pj->value)      // 排降序
            {
                pk = pj;
            }
        }

        if (pk!=pi)
        {
            _TYPE value = pk->value;
            pk->value = pi->value;
            pi->value = value;
        }
    }
}

3 使用示例

测试1:创建、添加到头尾、修改、删除节点、显示所有

void main()
{
    DLlist* pList =  _createList();  // 创建一个双链表
    addToHead(pList, 1);    // 插入数据到头
    addToHead(pList, 2);
    addToHead(pList, 3);
    addToHead(pList, 4);
    addToHead(pList, 5);

    addToBack(pList, 11); // 插入数据到尾
    addToBack(pList, 22);
    addToBack(pList, 33);
    addToBack(pList, 44);
    addToBack(pList, 55);

    showAll(pList); // 正向显示所有
    showAllReverse(pList); // 反向显示所有

    modify(pList, 11, 66);  // 将11修改为66
    showAll(pList); // 正向显示所有
    printf("size=%d\n", pList->size);

    deleteNode(pList, 33);
    showAll(pList); // 正向显示所有
    printf("size=%d\n", pList->size); // 双链表的大小

    system("pause");
}

输出:


[  5  4  3  2  1  11  22  33  44  55  ]

[  55  44  33  22  11  1  2  3  4  5  ]

[  5  4  3  2  1  66  22  33  44  55  ]
size=10

[  5  4  3  2  1  66  22  44  55  ]
size=9

测试2:删除一个范围、清空所有、截取前部分

void main()
{
    DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
    init(pList);

    addToHead(pList, 1);
    addToHead(pList, 2);
    addToHead(pList, 3);
    addToHead(pList, 4);
    addToHead(pList, 5);
    addToHead(pList, 6);
    addToHead(pList, 7);
    addToHead(pList, 8);
    addToHead(pList, 9);
    addToHead(pList, 10);

    showAll(pList);
    printf("size=%d\n", pList->size);  // 大小

    freeFrom(pList, 3);  // 从3开始,删除后面所有
    showAll(pList);
    printf("size=%d\n", pList->size);

    deleteRange(pList, 9, 3);  // 从9开始删除3个元素
    showAll(pList);
    printf("size=%d\n", pList->size);

    freeAll(pList); // 清空链表
    showAll(pList);
    printf("size=%d\n", pList->size);

    system("pause");
}

输出:


[  10  9  8  7  6  5  4  3  2  1  ]
size=10

[  10  9  8  7  6  5  4  ]
size=7

[  10  6  5  4  ]
size=4

log:showAll 空链表
size=0

测试3:删除头尾、查找、插入

void main()
{
    DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
    init(pList);

    addToHead(pList, 1);
    addToHead(pList, 2);
    addToHead(pList, 3);
    addToHead(pList, 4);
    addToHead(pList, 5);
    addToHead(pList, 6);
    showAll(pList);
    printf("size=%d\n", pList->size);

    //int ib = insertBefore(pList, 5, 66);
    int ib = insertBefore2(pList, 5, 66);   //5前面插入66
    if (ib)
    {
        printf("\n前插成功\n");
        showAll(pList);
        printf("size=%d\n", pList->size);
    }

    int ia = insertAfter(pList, 3, 26); //3后面插入26
    if (ia)
    {
        printf("\n后插成功\n");
        showAll(pList);
        printf("size=%d\n", pList->size);
    }

    DLNode* find = findByValue(pList, 6);  // 查找6
    if (find)
    {
        printf("\nfind ,value=%d,depth=%d\n", find->value, getDepth(pList, find->value));
    }

    DLNode* first = removeFirst(pList);  // 删除第一个节点并返回它
    if (first)
    {
        printf("\nfirst value=%d\n", first->value);
        showAll(pList);
        printf("size=%d\n", pList->size);
    }

    DLNode* last = removeLast(pList); // 删除最后一个节点并返回它
    if (last)
    {
        printf("\nlast value=%d\n", last->value);
        showAll(pList);
        printf("size=%d\n", pList->size);
    }

    system("pause");
}

输出:


[  6  5  4  3  2  1  ]
size=6

前插成功

[  6  66  5  4  3  2  1  ]
size=7

后插成功

[  6  66  5  4  3  26  2  1  ]
size=8

find ,value=6,depth=1

first value=6

[  66  5  4  3  26  2  1  ]
size=7

last value=1

[  66  5  4  3  26  2  ]
size=6

测试4:使用可变参数创建链表,并向链表中添加一个链表

void main()
{
    DLlist* pList = _createListWithValues(5, 2, 3, 4, 5, 6);
    DLlist* pnewList = _createListWithValues(5,11,22,33,44,55); 
    showAll(pList);
    showAll(pnewList);

    if (!checkNull(pList)&& !checkNull(pnewList))
    {
        addListToBack(pList, pnewList); // 将pnewList添加到pList尾部
    }

    showAll(pList);
    printf("size=%d\n", pList->size);


    system("pause");
}

输出:

[  2  3  4  5  6  ]

[  11  22  33  44  55  ]

[  2  3  4  5  6  11  22  33  44  55  ]
size=10

测试5:对链表元素进行排序

void main()
{
//  DLlist* pList = _createListWithValues(5, 2 ,8 , 4, 9, 7); // 创建一个包还5个元素(2 ,8 , 4, 9, 7)的链表

    int arr[5] = { 2 ,8 , 4, 9, 7 };
    DLlist* pList = _createListWithArrayValues(arr, 5);

    //showAllReverse(pList);
    sort(pList, _DESC);  // 降序
    showAll(pList);

    sort(pList, _ASC);  // 升序
    showAll(pList);

    // addToBackWithArrayValues(pList, arr, 3);  // 将一个数组的值添加到链表尾部
    //showAll(pList);

    system("pause");
}

输出:

[  9  8  7  4  2  ]

[  2  4  7  8  9  ]

三、实现像Java那样优雅的调用

在上面的例子中,使用链表的相关函数进行操作时,会感覚很凌乱,有时可能会令人困惑,这到底是对谁进行的操作。在Java中,使用集合类时,都是通过对象来调用方法,比如如下代码:

    List<String> mylist = new ArrayList<>();
    mylist.add("hello");
    mylist.add("world");
    mylist.add("haha");
    mylist.add("hi");
    mylist.remove(1);

我们可以很清楚的知道,是对list进行的操作,而且使用list进行调用会很方便,编译器会显示出所有可以被调用的方法。

为了实现类似这样的功能,我们需要对双链表的结构体定义进行改造,给其添加相关的函数指针成员,当创建双链表时,对这些函数指针进行初始化,指向之前调用的相应函数,这样当我们使用双链表时,就可以方便的进行调用了。函数指针相关知识可以参考 C语言 指针的细枝末节相关部分。

改造双链表结构体

对双链表结构体添加相关函数指针成员,如下所示:

注意:在函数指针的形参为链表结构体时,需要使用struct DoubleLinkList,而不能使用DLlist,因为这时候DLlist还未定义。

typedef struct DoubleLinkList
{
    DLNode* head;   // 链表头
    DLNode* back;  // 链表尾
    size_t size;    //链表包含的元素的个数 typedef unsigned int   size_t;  

    // pointers
    void (*init)(struct DoubleLinkList* pList);

    int (*addToHead)(struct DoubleLinkList* pList, _TYPE value);

    int (*addToBack)(struct DoubleLinkList* pList, _TYPE value);

    int (*addToHeadWithArrayValues)(struct DoubleLinkList* pList, _TYPE array[], int length);

    int (*addToBackWithArrayValues)(struct DoubleLinkList* pList, _TYPE array[], int length);

    int (*insertAfter)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);

    int (*insertAfter2)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);

    int (*insertBefore)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);

    int (*insertBefore2)(struct DoubleLinkList* pList, _TYPE curValue, _TYPE newValue);

    DLNode* (*removeFirst)(struct DoubleLinkList* pList);

    DLNode* (*removeLast)(struct DoubleLinkList* pList);

    void(*showAll)(struct DoubleLinkList* pList);

    void(*showAllWithRecursion)(DLNode* head);

    void(*showAllReverse)(struct DoubleLinkList* pList);

    void(*showAllReverseWithRecursion)(DLNode* back);

    int(*deleteNode)(struct DoubleLinkList* pList, _TYPE value);

    int(*deleteNode2)(struct DoubleLinkList* pList, _TYPE value);

    int(*deleteRange)(struct DoubleLinkList* pList, _TYPE fromValue, int count);

    int(*checkNull)(void* p);

    int(*modify)(struct DoubleLinkList* pList, _TYPE oldValue, _TYPE newValue);

    int(*freeAll)(struct DoubleLinkList* pList);

    int(*freeFrom)(struct DoubleLinkList* pList, _TYPE value);

    DLNode* (*findByValue)(struct DoubleLinkList* pList, _TYPE value);

    int(*addListToBack)(struct DoubleLinkList* pList, struct DoubleLinkList* addingList);

    int(*getDepth)(struct DoubleLinkList* pList, _TYPE value);

    int(*isEmpty)(struct DoubleLinkList* pList);

    void(*sort)(struct DoubleLinkList* pList, int asc);

}DLlist;  // 双链表 

改造创建链表的函数实现

在创建链表的函数,需要对相关的函数指针成员进行初始化,赋值对应的函数地址。如下代码:

// 给函数指针赋值
void initRefs(DLlist* pList){
    pList->init = init;
    pList->addToHead = addToHead;
    pList->addToBack = addToBack;
    pList->addToHeadWithArrayValues = addToHeadWithArrayValues;
    pList->addToBackWithArrayValues = addToBackWithArrayValues;
    pList->insertAfter = insertAfter;
    pList->insertAfter2 = insertAfter2;
    pList->insertBefore = insertBefore;
    pList->insertBefore2 = insertBefore2;
    pList->removeFirst = removeFirst;
    pList->removeLast = removeLast;
    pList->showAll = showAll;
    pList->showAllWithRecursion = showAllWithRecursion;
    pList->showAllReverse = showAllReverse;
    pList->showAllReverseWithRecursion = showAllReverseWithRecursion;
    pList->deleteNode = deleteNode;
    pList->deleteNode2 = deleteNode2;
    pList->deleteRange = deleteRange;
    pList->checkNull = checkNull;
    pList->modify = modify;
    pList->freeAll = freeAll;
    pList->freeFrom = freeFrom;
    pList->findByValue = findByValue;
    pList->addListToBack = addListToBack;
    pList->getDepth = getDepth;
    pList->isEmpty = isEmpty;
    pList->sort = sort; 
}

//用于给通过DoubleLinkList创建的新链表进行初始化
void init(DLlist* pList)
{
    pList->head = pList->back = NULL;
    pList->size = 0;
    initRefs(pList);  // 初始化
}

//快速创建一个双链表
DLlist* _createList()
{
    DLlist* pList = (DLlist*)malloc(sizeof(DLlist));
    init(pList);

    return pList;
}

这样就完成了改造,其他代码不需要进行修改。下面我们进行一下测试。

测试使用

#include"doublelinklist2.h"

void main(){

    DLlist* pList = _createList();
    pList->addToHead(pList, 1);    // 插入数据到头
    pList->addToHead(pList, 2);
    pList->addToHead(pList, 3);
    pList->addToHead(pList, 4);
    pList->addToHead(pList, 5);

    pList->addToBack(pList, 11); // 插入数据到尾
    pList->addToBack(pList, 22);
    pList->addToBack(pList, 33);
    pList->addToBack(pList, 44);
    pList->addToBack(pList, 55);

    pList->showAll(pList); // 正向显示所有
    pList->showAllReverse(pList); // 反向显示所有

    pList->modify(pList, 11, 66);  // 将11修改为66
    pList->showAll(pList); // 正向显示所有
    printf("size=%d\n", pList->size);

    pList->deleteNode(pList, 33);
    pList->showAll(pList); // 正向显示所有
    printf("size=%d\n", pList->size); // 双链表的大小



    system("pause");
}

现在,我们就可以轻松的通过链表来进行相关函数的调用,感覚还是很不错的。


源码

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值