卡码网语言基础课 | 15. 链表的基础操作III

1. 题目解析

// 链表的长度k
5
// 链表中的元素
1 2 3 4 5
// S行输入
3
// 在链表的第 n 个位置插入 x,n从1开始
// 1 2 3 3 4 5
4 3
// 1 2 4 3 3 4 5
3 4
// 如果插入位置不合法,则输出 Insertion position is invalid.
9 8
// L行输入
2
// 删除链表中的第m个元素
// 2 4 3 3 4 5
1
// 如果删除位置不合法,则输出 Deletion position is invalid.
0

2. 该题难点

1)在指定位置插入数值

在链表中,具体插入的过程如下:

  • 找到要插入的位置的前一个节点,将之命名为cur, 要插入的位置的下一个节点,将之命名为tmp, 它们之间的关系是cur -> next = tmp
  • 创建一个新的链表newNode, 将curnext指针指向newNode, 即cur -> next = nowNode
  • newNodenext指针指向tmp, 即newNode -> next = tmp

假设这样一个场景:在传递情报过程中,A的下线是B(也就是A -> next = B),现在我们要引入一个C充当A和B之间的中间人(即A的下线是C,C的下线是B)。

我们可以直接将A的next指向C(即A -> next = C),然后将C的next指向B(即C-> next = B)

但是B无法直接表示,之前是用A -> next来表示B的,现在A -> next已经指向C了,所以在操作之前,我们需要实现定义一个变量保存B,假设为tmp

    // 插入链表
    // 要插入的节点
    // 创建了一个新的 ListNode 结构的节点,值为x, 并将其地址赋给指针 newNode
    ListNode *newNode = new ListNode(x);

    // 要插入的位置的下一个节点
    // 创建了一个名为 tmp 的指针,临时存储当前节点 cur 的下一个节点的地址
    ListNode *tmp = cur -> next;

    // cur为要插入的位置的前一个节点
    // 将当前节点 cur 的 next 指针更新为指向新节点 newNode,将新节点插入到当前节点后面
    cur -> next = newNode;

    // 将新节点 newNode 的 next 指针设置为指向之前临时存储的节点 tmp
    newNode -> next = tmp;

2)删除指定位置的数值

只需要找到删除节点的前一个节点cur,并将其next 指针设置为指向当前节点的下下个节点,从而跳过了下一个节点,实现了节点的删除操作。

    // cur->next 表示当前节点 cur 的下一个节点
    // cur->next->next 表示要删除的节点的下一个节点
    // 当前节点 cur 的 next 指针不再指向要删除的节点,而是指向了要删除节点的下一个节点
    cur -> next = cur -> next -> next;

3)打印链表

    // 打印链表.
    void printLinklist(ListNode *headNode)
    {
        // 虚拟头结点接入链表
        ListNode *cur = headNode;
        // 什么时候链表迭代到最后一个节点呢?
        // 当前节点的下一个节点为NULL时说明下一个节点为空节点,即链表的末尾
        while(cur -> next != nullptr)
        {
            cout << cur -> next -> val << " ";
            cur = cur -> next;
        }
        cout << endl;
    }

3. 总结

#include <iostream>
using namespace std;

// 定义链表节点
struct ListNode
{
    int val;
    ListNode *next;
    // 初始化链表
    ListNode(int x) : val(x), next(nullptr) {}
};

// 打印链表
void printLinklist(ListNode *head)
{
    ListNode *cur = head;
    while(cur -> next != nullptr)
    {
        cout << cur -> next -> val << " ";
        // 更新尾节点
        cur = cur -> next;
    }
    cout << endl;
}

int main()
{
    int S, L, m, n, x, k, val;
    // 构造链表
    // 定义一个虚拟头结点,数据域为空
    ListNode *headNode = new ListNode(0);
    // 头结点为当前节点
    ListNode *cur = headNode;
    // 输入链表长度
    cin >> k;
    for(int i = 0; i < k; i++)
    {
        cin >> val;
        ListNode *newNode = new ListNode(val);
        // 将新节点接入链表
        cur -> next = newNode;
        // 更新尾节点
        cur = newNode;
    }
    
    //构建完毕,插入指定位置的值
    cin >> S;
    while(S--)
    {
        cin >> n >> x;
        // 插入位置不合法
        if(n > k || n <= 0)
        {
            cout << "Insertion position is invalid." << endl;
        }
        // 插入数值以及打印链表
        else
        {
            // 从虚拟头节点开始遍历,需要走n-1步
            cur = headNode;
            // 易错点1:寻找添加节点的位置,i从1开始,因为节点计数从1开始
            // 模拟一下n为1,链表长度为1
            // 找到要插入位置的前一个节点, 也就是第n-1个节点,
            for(int i = 1; i < n; i++)
            {
                cur = cur -> next;
            }
            
            // 插入链表节点
            // 构造一个要插入的节点
            ListNode *insert = new ListNode(x);
            // 构造一个临时节点,储存插入位置下一个节点的值
            ListNode *tmp = cur -> next;
            // A->B:A->C、C->B
            cur -> next = insert;
            insert  -> next = tmp;
            
            // 链表长度+1
            k++;
            // 打印链表
            printLinklist(headNode);
        }
    }
    
    // L行输入
    cin >> L;
    // 删除指定位置的值
    while(L--)
    {
        cin >> m;
        if(m > k || m <= 0)
        {
            cout << "Deletion position is invalid." << endl;
        }
        else
        {
            // 指针重新指向虚拟头结点,准备用cur遍历链表
            cur = headNode;
            // 易错点2:寻找删除节点的位置,i从1开始,因为节点计数从1开始
            // 找到要删除节点的前一个节点
            // 模拟一下m为1,链表长度为1
            for(int i = 1; i < m; i++)
            {
                cur = cur -> next;
            }
            
            // 删除链表节点
            cur -> next = cur -> next -> next;
            //链表长度-1
            k--;
            // 打印链表。如果删除节点后链表为空则不打印
            if(k != 0) printLinklist(headNode);
        }
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值