代码随想录--链表--设计链表

题目

题意:

在链表类中实现这些功能:

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

在这里插入图片描述

思路

删除链表节点:
在这里插入图片描述添加链表节点:
在这里插入图片描述这道题目设计链表的五个接口:

获取链表第index个节点的数值
在链表的最前面插入一个节点
在链表的最后面插入一个节点
在链表第index个节点前面插入一个节点
删除链表的第index个节点

可以说这五个接口,已经覆盖了链表的常见操作,是练习链表操作非常好的一道题目

链表操作的两种方式:

直接使用原来的链表来进行操作。
设置一个虚拟头结点在进行操作。

下面采用的设置一个虚拟头结点(这样更方便一些,大家看代码就会感受出来)。

class MyLinkedList {
public:
// 定义链表节点结构体
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};

// 初始化链表
MyLinkedList() {
    _dummyHead = new LinkedNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
    _size = 0;
}

// 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
int get(int index) {
    if (index > (_size - 1) || index < 0) {
        return -1;
    }
    LinkedNode* cur = _dummyHead->next;
    while(index--){ // 如果--index 就会陷入死循环
        cur = cur->next;
    }
    return cur->val;
}

// 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
void addAtHead(int val) {
    LinkedNode* newNode = new LinkedNode(val);
    newNode->next = _dummyHead->next;
    _dummyHead->next = newNode;
    _size++;
}

// 在链表最后面添加一个节点
void addAtTail(int val) {
    LinkedNode* newNode = new LinkedNode(val);
    LinkedNode* cur = _dummyHead;
    while(cur->next != nullptr){
        cur = cur->next;
    }
    cur->next = newNode;
    _size++;
}

// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果index大于链表的长度,则返回空
// 如果index小于0,则在头部插入节点
void addAtIndex(int index, int val) {

    if(index > _size) return;
    if(index < 0) index = 0;        
    LinkedNode* newNode = new LinkedNode(val);
    LinkedNode* cur = _dummyHead;
    while(index--) {
        cur = cur->next;
    }
    newNode->next = cur->next;
    cur->next = newNode;
    _size++;
}

// 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
void deleteAtIndex(int index) {
    if (index >= _size || index < 0) {
        return;
    }
    LinkedNode* cur = _dummyHead;
    while(index--) {
        cur = cur ->next;
    }
    LinkedNode* tmp = cur->next;
    cur->next = cur->next->next;
    delete tmp;
    //delete命令指示释放了tmp指针原本所指的那部分内存,
    //被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
    //如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
    //如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
    tmp=nullptr;
    _size--;
}

// 打印链表
void printLinkedList() {
    LinkedNode* cur = _dummyHead;
    while (cur->next != nullptr) {
        cout << cur->next->val << " ";
        cur = cur->next;
    }
    cout << endl;
}

private:
int _size;
LinkedNode* _dummyHead;

};

时间复杂度: 涉及 index 的相关操作为 O(index), 其余为 O(1)
空间复杂度: O(n)

Java

//单链表
class ListNode {
int val;
ListNode next;
ListNode(){}
ListNode(int val) {
this.val=val;
}
}
class MyLinkedList {
//size存储链表元素的个数
int size;
//虚拟头结点
ListNode head;

//初始化链表
public MyLinkedList() {
    size = 0;
    head = new ListNode(0);
}

//获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
public int get(int index) {
    //如果index非法,返回-1
    if (index < 0 || index >= size) {
        return -1;
    }
    ListNode currentNode = head;
    //包含一个虚拟头节点,所以查找第 index+1 个节点
    for (int i = 0; i <= index; i++) {
        currentNode = currentNode.next;
    }
    return currentNode.val;
}

//在链表最前面插入一个节点,等价于在第0个元素前添加
public void addAtHead(int val) {
    addAtIndex(0, val);
}

//在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
public void addAtTail(int val) {
    addAtIndex(size, val);
}

// 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果 index 大于链表的长度,则返回空
public void addAtIndex(int index, int val) {
    if (index > size) {
        return;
    }
    if (index < 0) {
        index = 0;
    }
    size++;
    //找到要插入节点的前驱
    ListNode pred = head;
    for (int i = 0; i < index; i++) {
        pred = pred.next;
    }
    ListNode toAdd = new ListNode(val);
    toAdd.next = pred.next;
    pred.next = toAdd;
}

//删除第index个节点
public void deleteAtIndex(int index) {
    if (index < 0 || index >= size) {
        return;
    }
    size--;
    if (index == 0) {
        head = head.next;
    return;
    }
    ListNode pred = head;
    for (int i = 0; i < index ; i++) {
        pred = pred.next;
    }
    pred.next = pred.next.next;
}

}

//双链表
class ListNode{
int val;
ListNode next,prev;
ListNode() {};
ListNode(int val){
this.val = val;
}
}

class MyLinkedList {

//记录链表中元素的数量
int size;
//记录链表的虚拟头结点和尾结点
ListNode head,tail;

public MyLinkedList() {
    //初始化操作
    this.size = 0;
    this.head = new ListNode(0);
    this.tail = new ListNode(0);
    //这一步非常关键,否则在加入头结点的操作中会出现null.next的错误!!!
    head.next=tail;
    tail.prev=head;
}

public int get(int index) {
    //判断index是否有效
    if(index<0 || index>=size){
        return -1;
    }
    ListNode cur = this.head;
    //判断是哪一边遍历时间更短
    if(index >= size / 2){
        //tail开始
        cur = tail;
        for(int i=0; i< size-index; i++){
            cur = cur.prev;
        }
    }else{
        for(int i=0; i<= index; i++){
            cur = cur.next; 
        }
    }
    return cur.val;
}

public void addAtHead(int val) {
    //等价于在第0个元素前添加
    addAtIndex(0,val);
}

public void addAtTail(int val) {
    //等价于在最后一个元素(null)前添加
    addAtIndex(size,val);
}

public void addAtIndex(int index, int val) {
    //index大于链表长度
    if(index>size){
        return;
    }
    //index小于0
    if(index<0){
        index = 0;
    }
    size++;
    //找到前驱
    ListNode pre = this.head;
    for(int i=0; i<index; i++){
        pre = pre.next;
    }
    //新建结点
    ListNode newNode = new ListNode(val);
    newNode.next = pre.next;
    pre.next.prev = newNode;
    newNode.prev = pre;
    pre.next = newNode;
    
}

public void deleteAtIndex(int index) {
    //判断索引是否有效
    if(index<0 || index>=size){
        return;
    }
    //删除操作
    size--;
    ListNode pre = this.head;
    for(int i=0; i<index; i++){
        pre = pre.next;
    }
    pre.next.next.prev = pre;
    pre.next = pre.next.next;
}

}

/**

  • Your MyLinkedList object will be instantiated and called as such:
  • MyLinkedList obj = new MyLinkedList();
  • int param_1 = obj.get(index);
  • obj.addAtHead(val);
  • obj.addAtTail(val);
  • obj.addAtIndex(index,val);
  • obj.deleteAtIndex(index);
    */
  • 25
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值