一起学《C程序设计》第十一课——链表及其操作

注意,请认真学习完《C程序设计(第五版)》第九章后再阅读本文会有更大的收获。

链表

概念理解

链表,用一条链来连接各个节点的数据。每个节点都会存储指向下一个节点的指针,最后一个节点指向一个空指针。

链表节点,通常节点会存储多种数据类型,一般采用结构体来定义。

链表与数组

如果把数组当作一种特殊的链表,虽然每个节点没有存储的指向下一个节点的指针,但是因为数组的独特性,我们可以根据数组类型来把当前节点指针做加法运算(元素数据类型所占内存的长度)就能得到下个节点的指针了。

链表存在的意义

数组在定义时需要指定长度,想要保证够用就需要把长度设置的足够长,这样会浪费存储空间,动态的根据需要进行扩展就是链表存在的意义。

链表操作

通过代码来练习链表的操作,链表一般结合动态内存分配进行运用,使用到之前学习的malloc()函数。

先定义一个结构体作为链表的节点,结构体里的*next成员指向同一个结构体。

typedef struct People{
    int index;
    char name[30];
    struct People *next;
} PEOPLE;

注意:这里使用typedef来给结构体重新命名,在使用的时候能够更加便捷。

初始化一个链表

用malloc()函数的好处在这里体现了,我们可以定义任意多个节点并且都使用指针来进行引用与赋值操作,无需为每个节点都定义一个变量名。

/*
* 初始化一个链表
* @param    int    link_list_length    链表长度
*/
static PEOPLE *initLinkList(int link_list_length) {
    PEOPLE *p, *previous, *start;
    int length = sizeof(PEOPLE);

    start = malloc(length);
    if (!start){
        return NULL;
    }

    start->index = 0;
    start->next = NULL;
    previous = start;

    for (int i = 1; i < link_list_length; i++){
        p = malloc(length);
        if (p){
            p->index = i;
            p->next = NULL;

            previous->next = p;
        }
        previous = p;
    }
    return start;
}

初始化之后的链表,我们通常使用首个节点的指针进行引用。

输出链表

使用while循环来输出链表节点中的数据,终止条件就是最后一个节点指向下一个节点的指针为NULL。

/*
* 输出链表
*/
static void printfLinkList(struct People *start) {
    printf("========BEGIN========\n");
    while (start != NULL){
        printf("struct index is: %d\n", start->index);
        start = start->next;
    }
    printf("========END========\n");
}

插入一个节点

插入到第N个节点的位置,那么原有的节点指向逻辑发生变化:原来的N-1节点指向新插入的N,新插入的N指向原来的N,也就是把原来的位置N变成了N+1。

/*
* 向链表中某个位置插入值
* @param    PEOPLE    start        链表起始节点指针
* @param    PEOPLE    insert        要插入的数据指针
* @param    int        position    插入的位置
*/
static PEOPLE *insertIntoLinkList(PEOPLE *start, PEOPLE *insert, int position) {
    PEOPLE *origin, *next;

    origin = start;
    if (start == NULL || position == 0){
        insert->next = start;
        origin = insert;
    } else{
        int i = 1;

        while (start != NULL){
            next = start->next;
            if (i == position){
                start->next = insert;
                insert->next = next;
            }

            i++;
            start = next;
        }
    }

    return origin;
}

删除某个节点

可以根据节点里的成员值删除,也可以像插入一样根据位置删除,这里代码示例根据节点里的成员值删除。

删除节点N也就意味着把原来的N-1节点从指向N节点变成指向N+1节点。

/*
* 删除链表中某个节点
* @param    PEOPLE    start    链表起始节点指针
* @param    int        index    删除的节点的成员index值
*/
static PEOPLE *removeFromLinkList(PEOPLE *start, int index) {
    PEOPLE *origin, *previous, *next;
    origin = start;
    previous = NULL;
    while (start != NULL){
        next = start->next;

        if (index == 0){
            origin = next;
            printf("remove index is: %d\n", start->index);
            break;
        }

        if (index == start->index && previous){
            previous->next = next;
            printf("remove index is: %d\n", start->index);
            break;
        }

        previous = start;
        start = next;
    }
    return origin;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值