C++算法练习-day7——707.设计链表

题目来源:. - 力扣(LeetCode)

题目思路分析

在编程中,链表是一种常见的数据结构,用于存储一系列元素,但与数组不同,链表中的元素在内存中不必连续存储。每个元素(称为节点)包含数据部分和一个指向下一个节点的指针。本题要求我们实现一个自定义的链表类MyLinkedList,支持以下操作:

  1. 获取指定位置的元素get(int index)方法,根据索引返回链表中的元素值,索引无效时返回-1。
  2. 在头部添加元素addAtHead(int val)方法,在链表头部插入一个新节点。
  3. 在尾部添加元素addAtTail(int val)方法,在链表尾部插入一个新节点。
  4. 在指定位置添加元素addAtIndex(int index, int val)方法,在链表的指定位置插入一个新节点。
  5. 删除指定位置的元素deleteAtIndex(int index)方法,删除链表中指定位置的节点。

为了高效实现这些操作,我们需要维护一个指向链表头部的指针(head),以及一个记录链表大小的变量(size)。使用虚拟头节点(dummy node)可以简化边界情况的处理,例如当index为0时,我们不需要特殊处理头部插入的情况。

代码实现与注解

实例:

复制代码
#include <algorithm> // 为了使用std::max  
  
struct ListNode {  
    int val;  
    ListNode *next;  
    ListNode(int x) : val(x), next(nullptr) {}  
};  
  
class MyLinkedList {  
public:  
    MyLinkedList() {  
        this->size = 0;  
        // 使用虚拟头节点简化操作  
        this->head = new ListNode(0);  
    }  
      
    // 获取指定位置的元素值  
    int get(int index) {  
        if (index < 0 || index >= size) {  
            return -1; // 索引无效,返回-1  
        }  
        ListNode *cur = head;  
        for (int i = 0; i <= index; i++) { // 循环到目标位置的后一个节点  
            cur = cur->next;  
        }  
        return cur->val; // 返回目标节点的值  
    }  
      
    // 在头部添加元素  
    void addAtHead(int val) {  
        addAtIndex(0, val);  
    }  
      
    // 在尾部添加元素  
    void addAtTail(int val) {  
        addAtIndex(size, val);  
    }  
      
    // 在指定位置添加元素  
    void addAtIndex(int index, int val) {  
        if (index > size) {  
            return; // 索引超出链表长度,不执行任何操作  
        }  
        index = max(0, index); // 确保索引不小于0  
        size++; // 链表长度加1  
        ListNode *pred = head;  
        for (int i = 0; i < index; i++) {  
            pred = pred->next;  
        }  
        ListNode *add = new ListNode(val);  
        add->next = pred->next; // 新节点的next指向原位置的下一个节点  
        pred->next = add; // 原位置的节点指向新节点  
    }  
      
    // 删除指定位置的元素  
    void deleteAtIndex(int index) {  
        if (index < 0 || index >= size) {  
            return; // 索引无效,不执行任何操作  
        }  
        size--; // 链表长度减1  
        ListNode *pred = head;  
        for (int i = 0; i < index; i++) {  
            pred = pred->next;  
        }  
        ListNode *p = pred->next; // 待删除节点  
        pred->next = pred->next->next; // 跳过待删除节点  
        delete p; // 释放待删除节点的内存  
    }  
  
private:  
    int size; // 链表长度  
    ListNode *head; // 链表头部指针(虚拟头节点)  
};

主函数部分:

复制代码
int main() {  
    MyLinkedList* obj = new MyLinkedList();  
    obj->addAtHead(1);  
    obj->addAtTail(3);  
    obj->addAtIndex(1, 2); // 链表现在是1->2->3  
    cout << obj->get(1) << endl; // 输出2  
    obj->deleteAtIndex(1); // 删除索引1处的节点,链表现在是1->3  
    cout << obj->get(1) << endl; // 输出3  
    delete obj;  
    return 0;  
}

知识点摘要

  1. 链表的基本概念:链表是一种链式存储结构,由一系列节点组成,每个节点包含数据部分和一个指向下一个节点的指针。
  2. 虚拟头节点:在链表头部添加一个不存储实际数据的虚拟节点,可以简化边界情况的处理。
  3. 动态内存管理 :使用newdelete关键字在C++中管理动态内存,确保在不再需要时释放内存,防止内存泄漏。
  4. 时间复杂度分析getaddAtHeadaddAtTailaddAtIndexdeleteAtIndex方法的时间复杂度均为O(n),其中n为链表长度。这是因为这些方法在最坏情况下都需要遍历链表的一部分或全部节点。

通过实现自定义链表,我们不仅加深了对链表的理解,还学会了如何在实际编程中运用这些概念。

相关推荐
1尢晞118 分钟前
Java学习
java·开发语言
毕设源码-赖学姐26 分钟前
【开题答辩全过程】以 基于python的电影推荐系统为例,包含答辩的问题和答案
开发语言·python
星辰_mya31 分钟前
Elasticsearch线上问题之慢查询
java·开发语言·jvm
Yu_Lijing33 分钟前
网络复习篇——网络基础(一)
网络·c++·笔记
前端小菜袅34 分钟前
PC端原样显示移动端页面方案
开发语言·前端·javascript·postcss·px-to-viewport·移动端适配pc端
Bella的成长园地34 分钟前
为什么c++中的条件变量的 wait() 函数需要配合while 循环或谓词?
c++·面试
Highcharts.js36 分钟前
如何使用Highcharts SVG渲染器?
开发语言·javascript·python·svg·highcharts·渲染器
charlee4436 分钟前
为什么现代 C++ 库都用 PIMPL?一场关于封装、依赖与安全的演进
c++·智能指针·raii·pimpl·编译防火墙·封装设计
郝学胜-神的一滴40 分钟前
超越Spring的Summer(一): PackageScanner 类实现原理详解
java·服务器·开发语言·后端·spring·软件构建
摇滚侠41 分钟前
Java,举例说明,函数式接口,函数式接口实现类,通过匿名内部类实现函数式接口,通过 Lambda 表达式实现函数式接口,演变的过程
java·开发语言·python