算法通关村第一关——链表挑战笔迹(青铜)

知识脉络

  1. 链表的概念
  2. 如何构建链表
  3. 操作链表

1. 链表的概念

1.1 单链表

让我们先假想创建单链表是一个综艺游戏,游戏开始,主持人A去路边随机抓人加入游戏,每当抓到人加入链表这个“游戏”中时,A先生便告诉他一条数字,然后告诉上一个加入游戏的人我们新拉入的人的位置。
在这里插入图片描述

让我们用术语来解释这个游戏(也就是链表)所构建的内容:

  1. 节点\结点(翻译原因了):每一个人+他们所知道的信息(数字+下一个人的位置)
  2. 第一个加入游戏的人:头节点
  3. 最后一个加入游戏的人:尾节点

这样我们的图便可以这样画:
在这里插入图片描述

虚拟节点:没懂

如此”链表“就构建好了,接下来让我们用代码实现一下。
代码版图

1.2 单链表的构建

第一步我们先得拉人,也就是创建节点

用c语言这样写:

typedef struct link{
    char elem;//数字
    struct link *next;//下一个人的位置
}Link;

因为leecode是如下方式,所以后面我们都会改成leecode的方法

struct ListNode {
    int val;
    struct ListNode *next;
};

用python

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

然后我们便可以尝试连接这些节点(这里需要记录头节点)

struct ListNode* initLink() {
    int n;
    struct ListNode* p;//头指针
    struct ListNode* temp = (struct ListNode*)//创建头节点
    temp->val = 0;
    temp->next = NULL;
    p = temp;//头指针指向头节点
    for(int i = 1; i <= 4; i++){
        struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
        newNode->val = i;
        newNode->next = NULL;
        temp->next = newNode;
        temp = newNode;
    }
}

创建链表

int main(){
    struct ListNode* head = initLink();
    return 0;
}

操作链表

当人们都加入游戏后,游戏开始,也就是可以开始操作链表了。

1、打印链表

嘉宾B到来,我们给他的任务是记录每一位路人的数字。知道的是,每个人都只知道下一个人的位置,并没有其他信息(比如他的前一个人在哪)。

于是我们想获得全部人的信息,便得从第一位加入的人开始遍历,直到最后一个人。也就是让他说出数字和下一个人的位置,然后记录数据,去下一个位置对下一个人做同样的操作。

这时就知道为什么再链表中要记录头节点了(见创建数组的代码),因为遍历时我们将从他开始。

void printLink(struct ListNode* head) {
    struct ListNode* temp = head;
    // 只要temp不为空,就打印他的数字和下一个人的位置
    while(temp != NULL){
        printf("%d ", temp->val);
        temp = temp->next;
    }
    printf("\n");
}

//当然我们也能统计人数(获取链表长度)
int32_t getLinkLength(struct ListNode* head) {
    struct ListNode* temp = head;
    int32_t count = 0;
    while(temp != NULL){
        count++;
        temp = temp->next;
    }
    return count;

测试效果

int main(){
    struct ListNode* head = initLink();//initLink()见上文
    printLink(head);
    return 0;
}

2、插入链表

嘉宾B得到的任务是拉入路人继续壮大“链表”。可以想到在链表最后加入,也只用重复创建链表时的操作便行,那如果要让这个人加入链表的任意位置呢?甚至是表头呢?

可以想到,新加入一个人时,只用告诉最多两个人就行。

情况一:表头(就是让新人当第一个人),就只告诉他数字和下一个人(以前表头)的位置。

不需要告诉原来表头先生,因为他并不需要知道前一个人的位置

情况二:表尾(就是让新人当最后一个人),就只告诉他数字,再告诉以前的表尾他的位置。

情况三:中间(就是让新人当中间人),这时用图比较好理解。假如加入的人叫Y,让X告诉Y:他原本知道的Z的位置,然后告诉X忘记Z吧,记住Y的位置。
在这里插入图片描述

让我们用代码来描述一下

struct ListNode* insertNode(struct ListNode* head, struct ListNode* node,int32_t position){
    if(head == NULL){
        // 空链表,直接返回新加入的节点
        return node;
    }
    int size = getLinkLength(head);//获取长度
    if(position > size){
        // 插入的位置大于链表长度,直接返回
        return head;
    }
    // 插入头部
    if(position == 1){
        node->next = head;
        head = node;//更改头节点
        return head;
    }

    struct ListNode* temp = head;
    int32_t count = 1;
    //找到插入位置的前一个节点
    while(count < position-1){
        temp = temp->next;
        count++;
    }
    //与两人沟通
    nodeInsert->next = temp->next;
    temp->next = node;
    
    return head;

测试一下

void testInsert(){
    struct ListNode* head = NULL;
    struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
    node->val = 1;
    // 插入第一个元素,现在链表是[1]
    head = insertLink(head, node);
    printLink(head);


    //插入第二个元素,现在链表是[1,2]
    node = (struct ListNode*)malloc(sizeof(struct ListNode));
    node->val = 2;
    head = insertLink(head, node,2);
    printLink(head);

    //中间插入一个3,插入后链表是[1,3,2]
    node = (struct ListNode*)malloc(sizeof(struct ListNode));
    node->val = 3;
    head = insertLink(head, node,3);
    printLink(head);
    }
}

删除链表

我们搞了这么久,天都黑了,这下有人不耐烦要离开了。(删除节点)

这时还是分情况:

一、最先来的人(头节点)想离开

二、中间某个人想离开,还是用图表示

A,B,C三人,B想离开,于是他把C的位置告诉了A,然后就离开了

三、最后来的人(尾节点)想离开

struct ListNode* deleteLink(struct ListNode* head,int position){
    if(head == NULL || position < 1){
        //不存在的人无法离开
        return head;
    }
    int size =getLength(head);
    if(position > size){
        printf("输入有误")
        return head;
    }
    if(position == 1){
        //头节点离开
        struct ListNode* temp = head;
        head = head->next;
        free(temp);//释放内存
        return head;
    }else{
        //中间某个人离开
        struct ListNode* temp = head;
        int count = 1;
        while(count < position-1){
            temp = temp->next;
            count++;
        }
        struct ListNode* temp2 = temp->next;
        temp->next = temp2->next;
        free(temp2);
        return head;
    }
}

测试一下

void testDeleteLink(){
    struct ListNode* p = NULL
    //创建0-9的链表
    p = initLink(p);
    printLink(p);

    // 删除头节点
    p = deleteLink(p,1);
    printLink(p);

    // 删除中间节点
    p = deleteLink(p,5);
    printLink(p);

    //删除尾节点
    p = deleteLink(p,9);
    printLink(p);
}

如此第一关便结束了,以后会继续迭代的,欢迎关注

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值