《C和指针》阅读笔记(11)---单链表数据结构的设计和实现(2)

本文是承接上文《C和指针》阅读笔记(11)—单链表数据结构的设计和实现的延续。提供第二种单链表的设计及实现方法。

link.h 详细信息已在注释中说明,仔细分析代码即可。

#ifndef _LINK_H
#define _LINK_H
/*
 * 本单链表接口使用宏实现
 * 该系列接口的设计与业务完全无关
 * 节点内存的分配与释放由调用者负责
 * 业务结构和逻辑可在此接口上再次封装
 *
 */

#ifdef __cplusplus
extern "C"
{
#endif


/**
 * @brief SL_HEAD 
 *      定义链表头结构
 *
 * @param name 链表头结构名,链表头就代表一个链表对象
 * @param type 链表节点结构名
 *
 * @return 
 */
#define SL_HEAD(name, type) \
    typedef struct \
    { \
        type *sl_head; \
    } name


/**
 * @brief SL_NODE 
 *      定义匿名节点指针结构体
 *
 * @param type 链表节点结构名
 *
 * @return 
 */
#define SL_NODE(type) \
    struct \
    { \
        struct type *sl_next; \
    }

/**
 * @brief SL_INSERT_HEAD 
 *      新节点头插入链表
 *
 * @param link 链表头指针
 * @param entry 新节点指针
 * @param field 节点成员名
 *
 * @return 
 */
#define SL_INSERT_HEAD(link, entry, field) \
    do \
    { \
        (entry)->field.sl_next = (link)->sl_head; \
        (link)->sl_head = (entry); \
    }while(0)

/**
 * @brief SL_INSERT_TAIL 
 *      新节点尾插入链表
 *
 * @param tail_entry 链表当前尾节点指针
 * @param entry 新节点指针
 * @param field 节点成员名
 *
 * @return 
 */
#define SL_INSERT_TAIL(tail_entry, entry, field) \
    do \
    { \
        (entry)->field.sl_next = (tail_entry)->field.sl_next; \
        (tail_entry)->field.sl_next = (entry); \
    }while(0)

// 获取链表头节点指针
#define SL_FIRST(link) ((link)->sl_head)
// 获取链表尾
#define SL_END(head)    NULL
// 获取下一个节点指针
#define SL_NEXT(entry, field) ((entry)->field.sl_next)

// 初始化链表头指针
#define	SL_HEAD_INIT(link) \
    do{SL_FIRST(link) = SL_END(link);}while(0)


// 遍历链表
#define SL_FOREACH(tmp, link, field) \
    for ((tmp) = SL_FIRST(link); (tmp) != SL_END(link); (tmp) = SL_NEXT(tmp, field))

// 移动头节点
#define SL_REMOVE_HEAD(link, field) \
    (link)->sl_head = (link)->sl_head->field.sl_next;

#ifdef __cplusplus
}
#endif
#endif //_LINK_H


main.c

#include <stdio.h>
#include <stdlib.h>
#include "link.h"

// 定义一个苹果结构体
typedef struct _apple_s
{
    SL_NODE(_apple_s) node;
    float price;
    char type;
}apple_t;

int test_case1()
{
    // 定义apple_link头指针结构体
    SL_HEAD(apple_link, apple_t);

    // 定义苹果链表
    apple_link link_apple;

    // 初始化苹果链表
    SL_HEAD_INIT(&link_apple);

    // 分配节点内存, 分配三个苹果
    // 链表宏接口不负责节点内存的分配
    apple_t apple1 = {.price = 0.1, .type = 1};
    apple_t apple2 = {.price = 0.2, .type = 2};
    apple_t apple3 = {.price = 0.3, .type = 3};

    // 节点头插入链表
    // 将苹果1、苹果2、苹果3依次插入苹果链表
    SL_INSERT_HEAD(&link_apple, &apple1, node);
    SL_INSERT_HEAD(&link_apple, &apple2, node);
    SL_INSERT_HEAD(&link_apple, &apple3, node);

    // 遍历链表节点
    // 打印链表上的苹果的详细信息
    apple_t *p = NULL;
    SL_FOREACH(p, &link_apple, node)
        printf("price=%f, type=%d\n", p->price, p->type);

    return 0;
}

int test_case2()
{
    // 定义apple_link头指针结构体
    SL_HEAD(apple_link, apple_t);

    // 定义链表
    apple_link link_apple;

    // 初始化链表
    SL_HEAD_INIT(&link_apple);

    // 分配节点内存
    // 链表宏接口不负责节点内存的分配
    apple_t apple1 = {.price = 0.1, .type = 1};
    apple_t apple2 = {.price = 0.2, .type = 2};
    apple_t apple3 = {.price = 0.3, .type = 3};

    SL_INSERT_HEAD(&link_apple, &apple1, node);
    // 节点尾插入链表
    SL_INSERT_TAIL(&apple1, &apple2, node);
    SL_INSERT_TAIL(&apple2, &apple3, node);

    // 遍历链表节点
    apple_t *p = NULL;
    SL_FOREACH(p, &link_apple, node)
        printf("price=%f, type=%d\n", p->price, p->type);

    return 0;
}

int test_case3()
{
    // 定义apple_link头指针结构体
    SL_HEAD(apple_link, apple_t);

    // 定义链表
    apple_link link_apple;

    // 初始化链表
    SL_HEAD_INIT(&link_apple);

    // 分配节点内存
    // 链表宏接口不负责节点内存的分配
    apple_t apple1 = {.price = 0.1, .type = 1};
    apple_t apple2 = {.price = 0.2, .type = 2};
    apple_t apple3 = {.price = 0.3, .type = 3};

    SL_INSERT_HEAD(&link_apple, &apple1, node);
    // 节点尾插入链表
    SL_INSERT_TAIL(&apple1, &apple2, node);
    SL_INSERT_TAIL(&apple2, &apple3, node);

    printf("移除头节点前:\n");
    // 遍历链表节点
    apple_t *p = NULL;
    SL_FOREACH(p, &link_apple, node)
        printf("price=%f, type=%d\n", p->price, p->type);

    // 移除头节点
    SL_REMOVE_HEAD(&link_apple, node);

    printf("移除头节点后:\n");
    p = NULL;
    SL_FOREACH(p, &link_apple, node)
        printf("price=%f, type=%d\n", p->price, p->type);
    return 0;
}


int main(int argc, char** argv)
{
    int n = atoi(argv[1]);

    switch(n)
    {
    case 1:
        test_case1();
        break;
    case 2:
        test_case2();
        break;
    case 3:
        test_case3();
        break;
    default:
        printf("not support operate\n");
    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sif_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值