Day_3 链表理论基础 、203.移除链表元素 、 707.设计链表 、206.反转链表

一、 链表理论基础
建议:了解一下链表基础,以及链表和数组的区别
文章链接:[https://programmercarl.com/%E9%93%BE%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html](https://programmercarl.com/%E9%93%BE%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html)

1.链表的定义:
```
// 单链表
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
    //注:结构体里面也可以有构造函数(前面两个是他的成员变量),他主要特点是访问权限是public
};
```
注:
## 1. ListNode线性链表定义(c++自带)

```cpp
struct ListNode{    
    int val;    
    ListNode *next;    
    ListNode() : val(0),next(NULL){}    
    ListNode(int x) : val(x), next(NULL){}    
    ListNode(int x, ListNode *next) : val(x), next(next){}
};
```

或者:
通过自己定义构造函数初始化节点:

```
ListNode* head = new ListNode(5);
```

使用默认构造函数初始化节点:

```
ListNode* head = new ListNode();
head->val = 5;
```
具体见
[链表 - OI Wiki (oi-wiki.org)](https://oi-wiki.org/ds/linked-list/)
再把链表的特性和数组的特性进行一个对比,如图所示:

![链表-链表与数据性能对比](https://code-thinking-1253855093.file.myqcloud.com/pics/20200806195200276.png)

数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。
链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。
### 203.移除链表元素
建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。
题目链接/文章讲解/视频讲解::[https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html](https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html)
状态:看题目理解移除单链表元素的基本操作

法一(正常思路):
**直接使用原来的链表来进行移除节点操作:**

```
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        // 删除头结点(特殊情况优先考虑)
        while (head != NULL && head->val == val) { // 注意这里不是if
            ListNode* tmp = head;
            head = head->next;
            delete tmp;
        }

        // 删除非头结点
        ListNode* cur = head;
        while (cur != NULL && cur->next!= NULL) {//因为下面是cur->next->val,所以要cur->next!= NULL
            if (cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } 
            else {
                cur = cur->next;
            }
        }
        return head;
    }
};
```
- 时间复杂度: O(n)
- 空间复杂度: O(1)

法二(新方法):
**设置一个虚拟头结点在进行移除节点操作:**(排除特殊情况)

```
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
        dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
        //或直接写 ListNode* dummyHead = new ListNode(0,head);
        ListNode* cur = dummyHead;
        while (cur!=NULL&&cur->next != NULL) {
            if(cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } 
            else {
                cur = cur->next;
            }
        }
        head = dummyHead->next;
        delete dummyHead;//记得delete
        return head;
    }
};
```

### 707.设计链表

建议: 这是一道考察 链表综合操作的题目,不算容易,可以练一练 使用虚拟头结点
题目链接/文章讲解/视频讲解:[https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html](https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html)
状态:未做出
题目代码就不附了,写几个易错点吧:
(1)struct中也可以有构造函数,默认访问权限是public
(2)类要先声明成员,再写函数
(3)函数返回值是void时,不符合的情况直接写return即可
(4)**尤其注意**```
delete tmp;
        //delete命令指示释放了tmp指针原本所指的那部分内存,
        //被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
        //如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
        //如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
        tmp=nullptr;
```
先做到这,未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值