数据结构篇之--链表(三)

目录

一、链表

二、链表优势

三、单向链表

1、结构体设计

2、接口设计

3、接口实现

四、单向循环链表

1、结构体设计

2、接口设计

3、接口实现

五、双向链表

1、结构体设计

2、接口设计

3、接口实现

六、双向循环链表

1、结构体设计

2、接口设计

3、接口实现

七、源码结构 && 测试

1、源码结构

2、编译

3、测试


一、链表

1、单向链表

2、单向循环链表

3、双向链表

4、双向循环链表

二、链表优势

1、使用堆内存,内存空间不要求连续,内存利用率高

2、增删方便

三、单向链表

1、结构体设计

设计头结点、普通节点(或者说链表节点)。

头结点:可以存储链表节点之外的数据,比如节点个数。设计头结点可以使得编程容易扩展以及方便操作

普通节点:数据域与指针域。由于是单向链表,指针域只需要一个 next 指向下一个节点即可(最后一个节点的 next 指针指向 NULL)。

/* 数据结构设计 */
typedef struct SIGLE_LINK_NODE
{
    struct SIGLE_LINK_NODE *next; // 指针域
    Data data;                    // 数据域
}SigleLinkNode;  // 普通节点

typedef struct
{
    SigleLinkNode *next;
    int numNode;
}SigleHeadNode;  // 头节点

 宏定义:

/* 宏定义 */
#define RET_INT_SUCC (0)
#define RET_INT_FAIL (-1)
#define RET_BOOL_SUCC true
#define RET_BOOL_FAIL false

#define PR_ERR(fmt, arg...)         fprintf(stderr, "\r\033[K\033[31m[%s][%d]:"fmt"\033[0m\n", __func__, __LINE__, ##arg)
#define PR_INFO(fmt, arg...)        fprintf(stderr, "\r\033[K\033[33m"fmt"\033[0m\n", ##arg)
#define PR_RESULT_SUCC(fmt, arg...) fprintf(stderr, "\r\033[K\033[32m"fmt"\033[0m\n", ##arg)
#define PR_RESULT_FAIL(fmt, arg...) fprintf(stderr, "\r\033[K\033[31m"fmt"\033[0m\n", ##arg)

#define CL_SCREEN() clear_screen()

2、接口设计

// 函数声明
// 1、初始化, 创建头节点
SigleHeadNode *initSigleLinkList();
// 2、创建普通节点
static SigleLinkNode *createNode(int id, int score);
// 3、判断是否为空链表
static bool isEmptyLinkList(SigleHeadNode* head);
// 4、添加一个新节点
// 尾插
static bool tailAddNode(SigleHeadNode *head, SigleLinkNode *newNode);
// 头插
static bool headAddNode(SigleHeadNode *head, SigleLinkNode *newNode);
// 5、查询一个节点,根据id来查询
static SigleLinkNode *queryNode(SigleHeadNode *head, int id);
// 6、删除一个节点,根据id来删除
static bool delNode(SigleHeadNode *head, int id);
// 7、打印链表
static void dumpLinkList(SigleHeadNode *head);
// 8、销毁链表
static bool destroyLinkList(SigleHeadNode *head);

3、接口实现

/* ***** 单向链表: 内部接口设计 START ***** */
// 1、初始化, 创建头节点
SigleHeadNode *initSigleLinkList()
{
    SigleHeadNode *head = calloc(1, sizeof(SigleHeadNode));
    if(NULL == head)
    {
        PR_ERR("calloc fail");
        return head;
    }

    head->numNode = 0;
    head->next = NULL;

    return head;
}

// 2、创建普通节点
static SigleLinkNode *createNode(int id, int score)
{
    SigleLinkNode *node = calloc(1, sizeof(SigleLinkNode));
    if(NULL == node)
    {
        PR_ERR("calloc fail");
        return node;
    }

    node->data.id = id;
    node->data.score = score;
    node->next = NULL;

    return node;
}

// 3、判断是否为空链表
static bool isEmptyLinkList(SigleHeadNode* head)
{
    if(NULL == head)
        return RET_BOOL_FAIL;

    if(0 == head->numNode)
        return RET_BOOL_SUCC;

    return RET_BOOL_FAIL;
}

// 4、添加一个新节点
// 尾插
static bool tailAddNode(SigleHeadNode *head, SigleLinkNode *newNode)
{
    SigleLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        head->next = newNode;
        head->numNode ++;
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while(NULL != node && NULL != node->next)
        node = node->next;

    node->next = newNode;
    head->numNode ++;
    return RET_BOOL_SUCC;
}
// 头插
static bool headAddNode(SigleHeadNode *head, SigleLinkNode *newNode)
{
    SigleLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    node = head->next;
    head->next = newNode;
    newNode->next = node;
    head->numNode ++;

    return RET_BOOL_SUCC;
}

// 5、查询一个节点,根据id来查询
static SigleLinkNode *queryNode(SigleHeadNode *head, int id)
{
    SigleLinkNode *node = NULL;

    if(NULL == head)
        return NULL;

    if(isEmptyLinkList(head))
        return NULL;

    node = head->next;
    while(NULL != node)
    {
        if(node->data.id == id)
            return node;
        node = node->next;
    }

    return NULL;
}

// 6、删除一个节点,根据id来删除
static bool delNode(SigleHeadNode *head, int id)
{
    SigleLinkNode *preNode = NULL;
    SigleLinkNode *node = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
        return RET_BOOL_FAIL;

    node = head->next;
    while(NULL != node)
    {
        if(node->data.id == id)
            break;

        preNode = node;
        node = node->next;
    }

    // not found
    if(NULL == node)
        return RET_BOOL_FAIL;

    // 如果要删掉的是首个节点
    if(id == head->next->data.id)
        head->next = node->next;
    else
        preNode->next = node->next;

    free(node);
    head->numNode --;

    return RET_BOOL_SUCC;
}

// 7、打印链表
static void dumpLinkList(SigleHeadNode *head)
{
    int i = 0;
    SigleLinkNode *node = NULL;

    if(NULL == head)
        return ;

    PR_INFO("numNode: %d", head->numNode);
    if(isEmptyLinkList(head))
        return ;

    node = head->next;

    while(NULL != node)
    {
        PR_INFO("number(%d): id(%d) score(%d)", ++i, node->data.id, node->data.score);
        node = node->next;
    }
}

// 8、销毁链表
static bool destroyLinkList(SigleHeadNode *head)
{
    SigleLinkNode *node = NULL;
    SigleLinkNode *nextNode = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        free(head);
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while(NULL != node)
    {
        nextNode = node->next;
        free(node);
        node = nextNode;
    }

    free(head);

    return RET_BOOL_SUCC;
}
/* ***** 单向链表: 内部接口设计 END ***** */

四、单向循环链表

1、结构体设计

结构体设计跟单向链表一致,区别在于单向循环链表的最后一个节点的 next 指针指向 head 头结点。整体上链表形成一个“环”。

/* 注:单向链表 && 单向循环链表
 * 区别在于:
 *      单向链表的末尾next指针指向 NULL
 *      单向循环链表的末尾next指针指向 head
 */

/* 数据结构设计 */
typedef struct SIGLE_CIRCULAR_LINK_NODE
{
    struct SIGLE_CIRCULAR_LINK_NODE *next; // 指针域
    Data data;                             // 数据域
}SigleCircularLinkNode;  // 普通节点

typedef struct
{
    struct SIGLE_CIRCULAR_LINK_NODE *next;
    int numNode;
}SigleCircularHeadNode;  // 头节点

#define TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head) (SigleCircularLinkNode *)head
/* *
 *  把指针域放在首个结构体成员,目的是作强制类型转换.
 *  如下:
 *  SigleCircularHeadNode *head = calloc(1, sizeof(SigleCircularHeadNode));
 *
 *  head->next = TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head); // like when initSigleCircularLinkList
 */

2、接口设计

// 函数声明
// 1、初始化, 创建头节点
SigleCircularHeadNode *initSigleCircularLinkList();
// 2、创建普通节点
static SigleCircularLinkNode *createNode(int id, int score);
// 3、判断是否为空链表
static bool isEmptyLinkList(SigleCircularHeadNode* head);
// 4、添加一个新节点
// 尾插
static bool tailAddNode(SigleCircularHeadNode *head, SigleCircularLinkNode *newNode);
// 头插
static bool headAddNode(SigleCircularHeadNode *head, SigleCircularLinkNode *newNode);
// 5、查询一个节点,根据id来查询
static SigleCircularLinkNode *queryNode(SigleCircularHeadNode *head, int id);
// 6、删除一个节点,根据id来删除
static bool delNode(SigleCircularHeadNode *head, int id);
// 7、打印链表
static void dumpLinkList(SigleCircularHeadNode *head);
// 8、销毁链表
static bool destroyLinkList(SigleCircularHeadNode *head);

3、接口实现

/* ***** 单向循环链表: 内部接口设计 START ***** */
// 1、初始化, 创建头节点
SigleCircularHeadNode *initSigleCircularLinkList()
{
    SigleCircularHeadNode *head = calloc(1, sizeof(SigleCircularHeadNode));
    if(NULL == head)
    {
        PR_ERR("calloc fail");
        return head;
    }

    head->numNode = 0;
    head->next = TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head);

    return head;
}

// 2、创建普通节点
static SigleCircularLinkNode *createNode(int id, int score)
{
    SigleCircularLinkNode *node = calloc(1, sizeof(SigleCircularLinkNode));
    if(NULL == node)
    {
        PR_ERR("calloc fail");
        return node;
    }

    node->data.id = id;
    node->data.score = score;
    node->next = NULL;

    return node;
}

// 3、判断是否为空链表
static bool isEmptyLinkList(SigleCircularHeadNode* head)
{
    if(NULL == head)
        return RET_BOOL_FAIL;

    if(0 == head->numNode)
        return RET_BOOL_SUCC;

    return RET_BOOL_FAIL;
}

// 4、添加一个新节点
// 尾插
static bool tailAddNode(SigleCircularHeadNode *head, SigleCircularLinkNode *newNode)
{
    SigleCircularLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        head->next = newNode;
        newNode->next = TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head);
        head->numNode ++;
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while( node->next != TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head) )
        node = node->next;

    node->next = newNode;
    newNode->next = TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head);
    head->numNode ++;
    return RET_BOOL_SUCC;
}
// 头插
static bool headAddNode(SigleCircularHeadNode *head, SigleCircularLinkNode *newNode)
{
    SigleCircularLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    node = head->next;
    head->next = newNode;
    newNode->next = node;
    head->numNode ++;

    return RET_BOOL_SUCC;
}

// 5、查询一个节点,根据id来查询
static SigleCircularLinkNode *queryNode(SigleCircularHeadNode *head, int id)
{
    SigleCircularLinkNode *node = NULL;

    if(NULL == head)
        return NULL;

    if(isEmptyLinkList(head))
        return NULL;

    node = head->next;
    while(node != TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head))
    {
        if(node->data.id == id)
            return node;
        node = node->next;
    }

    return NULL;
}

// 6、删除一个节点,根据id来删除
static bool delNode(SigleCircularHeadNode *head, int id)
{
    SigleCircularLinkNode *preNode = NULL;
    SigleCircularLinkNode *node = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
        return RET_BOOL_FAIL;

    node = head->next;
    while(node != TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head))
    {
        if(node->data.id == id)
            break;

        preNode = node;
        node = node->next;
    }

    // not found
    if(node == TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head))
        return RET_BOOL_FAIL;

    // 如果要删掉的是首个节点
    if(id == head->next->data.id)
        head->next = node->next;
    else
        preNode->next = node->next;

    free(node);
    head->numNode --;

    return RET_BOOL_SUCC;
}

// 7、打印链表
static void dumpLinkList(SigleCircularHeadNode *head)
{
    int i = 0;
    SigleCircularLinkNode *node = NULL;

    if(NULL == head)
        return ;

    PR_INFO("numNode: %d", head->numNode);
    if(isEmptyLinkList(head))
        return ;

    node = head->next;
    while(node != TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head))
    {
        PR_INFO("number(%d): id(%d) score(%d)", ++i, node->data.id, node->data.score);
        node = node->next;
    }
}

// 8、销毁链表
static bool destroyLinkList(SigleCircularHeadNode *head)
{
    SigleCircularLinkNode *node = NULL;
    SigleCircularLinkNode *nextNode = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        free(head);
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while(node != TO_SIGLE_CIRCULAR_LINKNODE_TYPE(head))
    {
        nextNode = node->next;
        free(node);
        node = nextNode;
    }

    free(head);

    return RET_BOOL_SUCC;
}
/* ***** 单向循环链表: 内部接口设计 END ***** */

五、双向链表

1、结构体设计

双向链表跟单向链表相比较,双向链表的链表节点的指针域多了一个 prev 节点,用于指向前一个节点。但对于 head 节点来说,head 的 prev 节点指向 NULL。

/* 注:单向链表 && 双向链表
 * 区别在于:
 *      单向链表的只有一个next指针指向下一个节点
 *      双向链表的存在prev指针指向前一个节点与next指针指向下一个节点
 */

/* 数据结构设计 */
typedef struct DOUBLY_LINK_NODE
{
    struct DOUBLY_LINK_NODE *prev;  // 指针域: 前驱指针
    struct DOUBLY_LINK_NODE *next;  // 指针域: 后驱指针
    Data data;                      // 数据域
}DoublyLinkNode;  // 普通节点

typedef struct
{
    DoublyLinkNode *prev;
    DoublyLinkNode *next;
    int numNode;
}DoublyHeadNode;  // 头节点

#define TO_DOUBLY_LINKNODE_TYPE(head) (DoublyLinkNode *)head

2、接口设计

// 函数声明
// 1、初始化, 创建头节点
DoublyHeadNode *initDoublyLinkList();
// 2、创建普通节点
static DoublyLinkNode *createNode(int id, int score);
// 3、判断是否为空链表
static bool isEmptyLinkList(DoublyHeadNode* head);
// 4、添加一个新节点
// 尾插
static bool tailAddNode(DoublyHeadNode *head, DoublyLinkNode *newNode);
// 头插
static bool headAddNode(DoublyHeadNode *head, DoublyLinkNode *newNode);
// 5、查询一个节点,根据id来查询
static DoublyLinkNode *queryNode(DoublyHeadNode *head, int id);
// 6、删除一个节点,根据id来删除
static bool delNode(DoublyHeadNode *head, int id);
// 7、打印链表
static void dumpLinkList(DoublyHeadNode *head);
// 8、销毁链表
static bool destroyLinkList(DoublyHeadNode *head);

3、接口实现

/* ***** 双向链表: 内部接口设计 START ***** */
// 1、初始化, 创建头节点
DoublyHeadNode *initDoublyLinkList()
{
    DoublyHeadNode *head = calloc(1, sizeof(DoublyHeadNode));
    if(NULL == head)
    {
        PR_ERR("calloc fail");
        return head;
    }

    head->numNode = 0;
    head->prev = NULL;
    head->next = NULL;

    return head;
}

// 2、创建普通节点
static DoublyLinkNode *createNode(int id, int score)
{
    DoublyLinkNode *node = calloc(1, sizeof(DoublyLinkNode));
    if(NULL == node)
    {
        PR_ERR("calloc fail");
        return node;
    }

    node->data.id = id;
    node->data.score = score;
    node->prev = NULL;
    node->next = NULL;

    return node;
}

// 3、判断是否为空链表
static bool isEmptyLinkList(DoublyHeadNode* head)
{
    if(NULL == head)
        return RET_BOOL_FAIL;

    if(0 == head->numNode)
        return RET_BOOL_SUCC;

    return RET_BOOL_FAIL;
}

// 4、添加一个新节点
// 尾插
static bool tailAddNode(DoublyHeadNode *head, DoublyLinkNode *newNode)
{
    DoublyLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        // head->prev = NULL;
        head->next = newNode;
        head->numNode ++;
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while(NULL != node && NULL != node->next)
        node = node->next;

    node->next = newNode;
    newNode->prev = node;
    head->numNode ++;
    return RET_BOOL_SUCC;
}
// 头插
static bool headAddNode(DoublyHeadNode *head, DoublyLinkNode *newNode)
{
    DoublyLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    node = head->next;
    if(NULL == node) // 添加的是首个链表节点
    {
        head->next = newNode;
        newNode->prev = TO_DOUBLY_LINKNODE_TYPE(head);
        newNode->next = NULL;
    }
    else
    {
        head->next = newNode;
        newNode->prev = TO_DOUBLY_LINKNODE_TYPE(head);
        newNode->next = node;
        node->prev = newNode;
    }
    head->numNode ++;

    return RET_BOOL_SUCC;
}

// 5、查询一个节点,根据id来查询
static DoublyLinkNode *queryNode(DoublyHeadNode *head, int id)
{
    DoublyLinkNode *node = NULL;

    if(NULL == head)
        return NULL;

    if(isEmptyLinkList(head))
        return NULL;

    node = head->next;
    while(NULL != node)
    {
        if(node->data.id == id)
            return node;
        node = node->next;
    }

    return NULL;
}

// 6、删除一个节点,根据id来删除
static bool delNode(DoublyHeadNode *head, int id)
{
    DoublyLinkNode *preNode = NULL;
    DoublyLinkNode *node = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
        return RET_BOOL_FAIL;

    node = head->next;
    while(NULL != node)
    {
        if(node->data.id == id)
            break;

        preNode = node;
        node = node->next;
    }

    // not found
    if(NULL == node)
        return RET_BOOL_FAIL;

    // 最后一个
    if(NULL == node->next)
    {
        node->prev->next = NULL;
    }
    else
    {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }

    free(node);
    head->numNode --;

    return RET_BOOL_SUCC;
}

// 7、打印链表
static void dumpLinkList(DoublyHeadNode *head)
{
    int i = 0;
    DoublyLinkNode *node = NULL;

    if(NULL == head)
        return ;

    PR_INFO("numNode: %d", head->numNode);
    if(isEmptyLinkList(head))
        return ;

    node = head->next;
    while(NULL != node)
    {
        PR_INFO("number(%d): id(%d) score(%d)", ++i, node->data.id, node->data.score);
        node = node->next;
    }
}

// 8、销毁链表
static bool destroyLinkList(DoublyHeadNode *head)
{
    DoublyLinkNode *node = NULL;
    DoublyLinkNode *nextNode = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        free(head);
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while(NULL != node)
    {
        nextNode = node->next;
        free(node);
        node = nextNode;
    }

    free(head);

    return RET_BOOL_SUCC;
}
/* ***** 双向链表: 内部接口设计 END ***** */

六、双向循环链表

1、结构体设计

/* 注:双向链表 && 双向循环链表
 * 区别在于:
 *      双向链表的head节点的prev指向NULL, 最后一个节点的next指向NULL
 *      双向循环链表的head节点的prev指向最后一个节点, 最后一个节点的next指向head
 */

/* 数据结构设计 */
typedef struct DOUBLY_CIRCULAR_LINK_NODE
{
    struct DOUBLY_CIRCULAR_LINK_NODE *prev;  // 指针域: 前驱指针
    struct DOUBLY_CIRCULAR_LINK_NODE *next;  // 指针域: 后驱指针
    Data data;                      // 数据域
}DoublyCircularLinkNode;  // 普通节点

typedef struct
{
    DoublyCircularLinkNode *prev;
    DoublyCircularLinkNode *next;
    int numNode;
}DoublyCircularHeadNode;  // 头节点

#define TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head) (DoublyCircularLinkNode *)head

2、接口设计

// 函数声明
// 1、初始化, 创建头节点
DoublyCircularHeadNode *initDoublyLinkList();
// 2、创建普通节点
static DoublyCircularLinkNode *createNode(int id, int score);
// 3、判断是否为空链表
static bool isEmptyLinkList(DoublyCircularHeadNode* head);
// 4、添加一个新节点
// 尾插
static bool tailAddNode(DoublyCircularHeadNode *head, DoublyCircularLinkNode *newNode);
// 头插
static bool headAddNode(DoublyCircularHeadNode *head, DoublyCircularLinkNode *newNode);
// 5、查询一个节点,根据id来查询
static DoublyCircularLinkNode *queryNode(DoublyCircularHeadNode *head, int id);
// 6、删除一个节点,根据id来删除
static bool delNode(DoublyCircularHeadNode *head, int id);
// 7、打印链表
static void dumpLinkList(DoublyCircularHeadNode *head);
// 8、销毁链表
static bool destroyLinkList(DoublyCircularHeadNode *head);

3、接口实现

/* ***** 双向循环链表: 内部接口设计 START ***** */
// 1、初始化, 创建头节点
DoublyCircularHeadNode *initDoublyCircularLinkList()
{
    DoublyCircularHeadNode *head = calloc(1, sizeof(DoublyCircularHeadNode));
    if(NULL == head)
    {
        PR_ERR("calloc fail");
        return head;
    }

    head->numNode = 0;
    head->prev = TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head);
    head->next = TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head);

    return head;
}

// 2、创建普通节点
static DoublyCircularLinkNode *createNode(int id, int score)
{
    DoublyCircularLinkNode *node = calloc(1, sizeof(DoublyCircularLinkNode));
    if(NULL == node)
    {
        PR_ERR("calloc fail");
        return node;
    }

    node->data.id = id;
    node->data.score = score;
    node->prev = NULL;
    node->next = NULL;

    return node;
}

// 3、判断是否为空链表
static bool isEmptyLinkList(DoublyCircularHeadNode* head)
{
    if(NULL == head)
        return RET_BOOL_FAIL;

    if(0 == head->numNode)
        return RET_BOOL_SUCC;

    return RET_BOOL_FAIL;
}

// 4、添加一个新节点
// 尾插
static bool tailAddNode(DoublyCircularHeadNode *head, DoublyCircularLinkNode *newNode)
{
    DoublyCircularLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        head->prev = newNode;
        head->next = newNode;
        newNode->prev = TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head);
        newNode->next = TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head);
        head->numNode ++;
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while(node->next != TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head))
        node = node->next;

    node->next->prev = newNode;
    newNode->next = node->next;
    newNode->prev = node;
    node->next = newNode;
    head->numNode ++;
    return RET_BOOL_SUCC;
}
// 头插
static bool headAddNode(DoublyCircularHeadNode *head, DoublyCircularLinkNode *newNode)
{
    DoublyCircularLinkNode *node = NULL;

    if(NULL == head || NULL == newNode)
        return RET_BOOL_FAIL;

    node = head->next;
    head->next = newNode;
    newNode->prev = TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head);
    newNode->next = node;
    node->prev = newNode;
    head->numNode ++;

    return RET_BOOL_SUCC;
}

// 5、查询一个节点,根据id来查询
static DoublyCircularLinkNode *queryNode(DoublyCircularHeadNode *head, int id)
{
    DoublyCircularLinkNode *node = NULL;

    if(NULL == head)
        return NULL;

    if(isEmptyLinkList(head))
        return NULL;

    node = head->next;
    while( node != TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head) )
    {
        if(node->data.id == id)
            return node;
        node = node->next;
    }

    return NULL;
}

// 6、删除一个节点,根据id来删除
static bool delNode(DoublyCircularHeadNode *head, int id)
{
    DoublyCircularLinkNode *node = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
        return RET_BOOL_FAIL;

    node = head->next;
    while(node != TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head))
    {
        if(node->data.id == id)
            break;

        node = node->next;
    }

    // not found
    if(node == TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head))
        return RET_BOOL_FAIL;

    node->prev->next = node->next;
    node->next->prev = node->prev;

    free(node);
    head->numNode --;

    return RET_BOOL_SUCC;
}

// 7、打印链表
static void dumpLinkList(DoublyCircularHeadNode *head)
{
    int i = 0;
    DoublyCircularLinkNode *node = NULL;

    if(NULL == head)
        return ;

    PR_INFO("numNode: %d", head->numNode);
    if(isEmptyLinkList(head))
        return ;

    node = head->next;
    while(node != TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head))
    {
        PR_INFO("number(%d): id(%d) score(%d)", ++i, node->data.id, node->data.score);
        node = node->next;
    }
}

// 8、销毁链表
static bool destroyLinkList(DoublyCircularHeadNode *head)
{
    DoublyCircularLinkNode *node = NULL;
    DoublyCircularLinkNode *nextNode = NULL;

    if(NULL == head)
        return RET_BOOL_FAIL;

    if(isEmptyLinkList(head))
    {
        free(head);
        return RET_BOOL_SUCC;
    }

    node = head->next;
    while(node != TO_DOUBLY_CIRCULAR_LINKNODE_TYPE(head))
    {
        nextNode = node->next;

        // node->prev->next = node->next;
        // node->next->prev = node->prev;
        free(node);

        node = nextNode;
    }

    free(head);

    return RET_BOOL_SUCC;
}
/* ***** 双向循环链表: 内部接口设计 END ***** */

七、源码结构 && 测试

1、源码结构

### tree 命令查看
LINK_LIST/
├── include
│   ├── common.h
│   ├── doubly_circular_linklist.h
│   ├── doubly_linklist.h
│   ├── sigle_circular_linklist.h
│   └── sigle_linklist.h
└── src
    ├── common.c
    ├── doubly_circular_linklist.c
    ├── doubly_linklist.c
    ├── main.c
    ├── sigle_circular_linklist.c
    └── sigle_linklist.c

2 directories, 11 files

源码下载:通过网盘分享的文件:link_list.zip
链接: https://pan.baidu.com/s/19DC1t6ICAuCM8etoS1mDOw 提取码: akmx

2、编译

LINK_LIST$ gcc src/*.c -I./include/ -o link_list

3、测试

1、请选择要选择测试的链表结构:

2、测试接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值