2021-10-03:室友自学c语言的第五天--单向链表

国庆节快乐呀。

今天在学链表,下面是我个人对链表的理解:

链表是结构体中存放一个指针,使之指向下一个结构体的数据结构。
小明在打开鞋柜的之后,拿出了a同学的鞋子,同时又发现一张纸条,是b同学鞋柜号码。这样b同学就可以不用给小明纸条,也能拿到自己的鞋子。
因为是结构体,鞋柜里不一定只有纸条,还可能有书本,水杯等东西。但存放这些东西的还是鞋柜。
想要遍历链表,只需要一扇一扇地打开鞋柜,顺着纸条找下一个鞋柜,就行了。
插入结点的时候,将前鞋柜的纸条放入此鞋柜,写一张此鞋柜的纸条放入前鞋柜。成为一条链。想象一下过程,其实很简单。
删除结点的时候,将此鞋柜的纸条放入前鞋柜,清空,就行了。
寻找结点,就是在遍历的时候打开鞋柜看一眼,看见目标鞋子就停下。
 

基础知识:

1.链表与结点不同,并不是一开始就分配好内存。链表在增加结点的时候需要用<malloc>库里面的malloc函数分配内存。

2.用typedef对结构体重命名,可以增加可读性,提高编码速度

3.结点分为数据域和指针域,数据域负责存储数据,指针域赋值为结点指引方向

4.尾结点的后继结点是空结点

以下是代码(参考了各位csdn大佬)侵删

 c语言链表详解(超详细)_Endeavor_G的博客-CSDN博客_c语言链表https://blog.csdn.net/Endeavor_G/article/details/80552680(4条消息) ❤️《画解数据结构》七个动图,画解链表❤️_英雄哪里出来-CSDN博客https://blog.csdn.net/WhereIsHeroFrom/article/details/119381711

#include <stdio.h>
#include <malloc.h>

typedef struct student {
    int score;
    struct student* next;
}Linklist;

下面是函数:

首先是创建链表,这里我使用的是尾插法。尾插法就是:当一个新结点插入的时候,它会站到现在的尾结点后面,喊一声“我才是尾结点”,然后它就成新尾结点了。

Linklist* create(int n) {
    Linklist* head, * node, * end;
    head = (Linklist*)malloc(sizeof(Linklist));
    end = head;
    end->next = NULL;
    for (int i = 0; i < n; i++) {
        node = (Linklist*)malloc(sizeof(Linklist));
        scanf_s("%d", &node->score);
        end->next = node; //第二个结点是node
        end = node;       //尾结点变成这个node
    }
    end->next = NULL;
    return head;
}

接着是销毁链表

为了便于自己理解,我把nextnode和temp想象成逃跑者与帮助逃跑者。请留意一下销毁链表与清空链表的不同。

//销毁链表
void destroy(Linklist* list) {
    if (list == NULL) {
        return;
    } //若本来就为空,返回(不清空头结点)
    Linklist* temp = list->next;//游标指针temp,
    while (temp != NULL) {
        Linklist* nextnode = temp->next;  //用nextnode帮助temp逃逸,
        free(temp);                       //释放temp足迹
        temp = nextnode;                  //temp逃逸
    }
    //释放头结点
    free(list);
    //重新置空头结点指针
    list = NULL;

下面是清空链表:

//清空链表
void clear(Linklist* list) {
    if (list == NULL) {
        return;
    }
    Linklist* temp = list->next;
    while (temp != NULL) {
        Linklist* nextnode = temp->next;
        free(temp);
        temp = nextnode;
    }
    list->next = NULL;
}

清空链表释放头结点的后继结点,而销毁链表不仅要释放头结点的后继结点,还要释放头结点。销毁链表后,除非再初始化一次链表,否则是无法写入任何数据的。

改变结点的值:

先在链表中寻找第n个结点,然后给出scanf函数更改它的值

//改变结点
void change(Linklist* list, int n) {
    Linklist* temp = list; // 游标指针temp指向list
    int i = 0;
    while (i < n && temp != NULL) {  //寻找第n个节点
        temp = temp->next;
        i++;
    }
    if (temp != NULL) {
        scanf_s("%d", &temp->score);
    }
    else {
        puts("no this node");
    }
}

删除结点:

要设置一个in跟踪t(成为t的前驱结点),在删除t的时候便于将t的前驱和后继结点相连接起来。

void delet(Linklist* list, int n) {
    Linklist* t = list;
    Linklist* in=NULL;
    int i = 0;
    while (i < n && t != NULL) {
        in = t;        //in是t的前驱结点
        t = t->next;
        i++;
    }
    if (t != NULL) {
        in->next = t->next;//找到了t,释放,in指向t的后继结点
        free(t);
    }
    else {
        puts("no this node");
    }
}

插入结点:

这里使用的是后插法,也就是插到n的后面。

先找到结点n,设置它的插入结点in,给in输入score。

插入的时候,让in指向n的后继结点,让n指向in就行了。

//插入结点
void insert(Linklist* list, int n) {
    Linklist* t = list, * in;
    int i = 0;
    while (i < n && t != NULL) {
        t = t->next;
        i++;
    }
    if (t != NULL) {
        in = (Linklist*)malloc(sizeof(Linklist));
        scanf_s("%d", &in->score);
        in->next = t->next;
        t->next = in;
    }
    else {
        puts("no this node");
    }
}

查询结点:

查询结点需要返回,而且返回类型是Linklist*

//查询结点
Linklist* getnode(Linklist* list, int n) {
    Linklist* temp = list;//设置游标指针
    int i = 0;
    while (temp != NULL && i < n) {
        temp = temp->next;
        ++i;
    }
    if (temp == NULL || i > n) {
        printf("no this node");
        return NULL;
    }
    return temp;
}

求链表长度

注意函数类型要与函数返回值相同,长度length用的是int类型,那么函数也应该用int类型

//链表长度
int listlength(Linklist* list) {
    Linklist* temp = list;
    int length = 0;
    while (temp->next != NULL) {
        temp = temp->next;
        ++length;
    }
    return length;
}

打印链表

void print(Linklist* list) {
    Linklist* h = list;
    while (h->next != NULL) {
        h = h->next;
        printf("%d ->", h->score);
    }
    printf("NULL\n");
}

下面是主函数

int main()
{

    int n, f;                //n为节点,f为功能
    Linklist* list; //声明list指针为空指针
    printf("create node number:");
    scanf_s("%d", &n);
    list = create(n);
    printf("_______________________________\ninside node:\n\n");
    print(list);
    n = 0;
    int flag = 1;
    while (flag == 1) {
        printf("_______________________________\nwhat can i do?:\n1.change\n2.delet\n3.insert\n4.getnode\n5.destroy\n6.clear\n7.create\n8.listlength\n0.out\n_______________________________\n");
        scanf_s("%d", &f);
        if (1 == f) {
            printf("change node:");
            scanf_s("%d", &n);
            change(list, n);
            printf("_______________________________\ninside node:\n\n");
            print(list);
        }
        else if (2 == f) {
            printf("delet node:");
            scanf_s("%d", &n);
            delet(list, n);
            printf("_______________________________\ninside node:\n\n");
            print(list);
        }
        else if (3 == f) {
            printf("insert node:");
            scanf_s("%d", &n);
            insert(list, n);
            printf("_______________________________\ninside node:\n\n");
            print(list);
        }
        else if (4 == f) {
            printf("getnode:");
            scanf_s("%d", &n);
            Linklist* temp;
            temp = getnode(list, n);
            printf("%d\n", *temp);
        }
        else if (5 == f) {
            destroy(list);
            printf("now list is destroy\n");
            flag = 0;
        }
        else if (6 == f) {
            clear(list);
            printf("now list is clear\n");
        }
        else if (7 == f) {
            Linklist* list; //声明list指针为空指针
            printf("create node number:");
            scanf_s("%d", &n);
            list = create(n);
            printf("_______________________________\ninside node:\n\n");
            print(list);
        }
        else if (8 == f) {
            int temp = listlength(list);
            printf("length:%d\n",temp);
        }

        else if (0 == f) {
            printf("bye!");
            flag = 0;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值