纯小白自学代码随想录笔记(每日更新)

c++编程基础约等于0,记录看代码随想录时不懂的问题,部分答案来源于chatgpt,部分是自己总结的。

数组

2.二分查找

前提:数组为有序数组数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的

704.二分查找

题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

版本2代码:

// 版本二
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

(1)"Solution" 是一个类的名称。在这里,它表示一个解决特定问题的类。通常情况下,在编程中,"Solution" 类可能包含解决某个具体问题的方法或算法。在这段代码中,"Solution" 类包含了一个名为 "search" 的公有方法,该方法接受一个整数数组和一个目标值作为输入,并返回目标值在数组中的索引,如果目标值不存在于数组中则返回 -1。

(2)在这段代码中,"public" 是一个访问修饰符,用于指定类成员的访问级别。在 C++ 中,它用于声明类的成员(方法和变量)可以在类的外部访问。在这里,"public" 表示该方法是公有的,可以在类外部被调用和访问。

(3)int search(vector<int>& nums, int target)是一个函数声明,它声明了一个名为 `search` 的函数,该函数接受两个参数:1. `vector<int>& nums`:这是一个引用类型的参数,表示一个整数向量(即整数数组),名为 `nums`,在函数内部对这个向量的修改会影响到函数外部传入的向量。2. `int target`:这是一个整数类型的参数,表示目标值,即要在数组中搜索的值。函数的返回类型是 `int`,表示返回一个整数值。

(4)`nums.size()` 是一个函数调用,它用于获取 `nums` 这个向量(或数组)的大小,即其中包含的元素个数。在 C++ 的标准库中,`size()` 是一个成员函数,用于返回容器中元素的数量。

(5)int middle = left + ((right - left) >> 1)这段代码使用了位运算右移操作符 `>>` 来计算中间位置 `middle`。这种写法与除以 2 的效果是一样的,但在一些情况下可能比除法运算更高效。位运算右移操作符 `>>` 将一个数的二进制表示向右移动指定的位数,相当于对这个数进行了除以 2 的操作。因此,`(right - left) >> 1` 的结果是搜索区间的长度的一半,再加上 `left` 就得到了搜索区间的中间位置 `middle`。这种写法与常规的除法运算相比,可能会更加高效,因为位运算在某些平台上的实现可能会更快。因此,这种写法在性能要求较高的场景下可能会被选择。

34. 在排序数组中查找元素的第一个和最后一个位置(链接)

题目:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。进阶:你可以设计并实现时间复杂度为 $O(\log n)$ 的算法解决此问题吗?

解法一链接

寻找右边界思路:采用while (left <= right)的写法,区间定义为[left, right],即左闭右闭的区间。官方说因为取左闭右闭的区间时,left==right也是有意义的,所以<=。

// 二分查找,寻找target的右边界(不包括target)
// 如果rightBorder为没有被赋值(即target在数组范围的左边,例如数组[3,3],target为2),为了处理情况一
int getRightBorder(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
    int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
    while (left <= right) { // 当left==right,区间[left, right]依然有效
        int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
        if (nums[middle] > target) {
            right = middle - 1; // target 在左区间,所以[left, middle - 1]
        } else { // 当nums[middle] == target的时候,更新left,这样才能得到target的右边界
            left = middle + 1;
            rightBorder = left;
        }
    }
    return rightBorder;
}

寻找左边界:

// 二分查找,寻找target的左边界leftBorder(不包括target)
// 如果leftBorder没有被赋值(即target在数组范围的右边,例如数组[3,3],target为4),为了处理情况一
int getLeftBorder(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
    int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
    while (left <= right) {
        int middle = left + ((right - left) / 2);
        if (nums[middle] >= target) { // 寻找左边界,就要在nums[middle] == target的时候更新right
            right = middle - 1;
            leftBorder = right;
        } else {
            left = middle + 1;
        }
    }
    return leftBorder;
}

(1)其中nums[middle]<=target时,left = middle +1; rightBorder = left;理解:因为left<=right时会一直循环,直到left>right结束循环,所以可以直接在循环里面让rightborder = left。因为该代码中right右边一定大于target,left左边一定小于等于target,一直循环到left在right右边一格时,就找到了右边界,即left所在位置。(相当于通过leff跟right左右夹击找到target)

(2)怎么确定if后面nums[middle]是>还是>=:举个例子:

首先先明确二分法是靠Left和Right左右夹击找出需要的位置,即R右边满足什么条件,L左边满足什么条件,从而夹击出RL是一个交界。所以找左边界就在图中7和8的位置夹击,找右边界就在图中8和100的位置夹击,更新Right肯定是target小于middle或者target小于等于middle才更新right,此时不确定用不用写等于,观察到找左边界时,Right右边的数应该是大于等于target,所以更新R时应该是nums[middle]>=target,那么R=Middle-1的右边就是大于等于target;观察到找左边界时,L左边的数应该是小于target,那如果nums[middle]<target时,L=M+1的左边就是小于target。找右边界同理。(感觉我这么想有点绕。。。有没有更简洁的想法求指教)

解法二视频链接

配合视频讲解
:找左边界(lower_bound函数):关键:循环不变量,L-1始终是小于target,R+1始终是大于等于target。根据循环不变量,R+1是我们要找的答案,由于循环结束后R+1=L,所以答案也可以用L表示。

精妙绝伦的是:大于、大于等于、小于、小于等于都可以转化为找大于等于的,所以找左边界:start = lower_bound(nums,target),end = lower_bound(nums,target + 1) - 1

代码:

class Solution {
    // lower_bound 返回最小的满足 nums[i] >= target 的 i
    // 如果数组为空,或者所有数都 < target,则返回 nums.size()
    // 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]

    // 闭区间写法
    int lower_bound(vector<int> &nums, int target) {
        int left = 0, right = (int) nums.size() - 1; // 闭区间 [left, right]
        while (left <= right) { // 区间不为空
            // 循环不变量:
            // nums[left-1] < target
            // nums[right+1] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                left = mid + 1; // 范围缩小到 [mid+1, right]
            else
                right = mid - 1; // 范围缩小到 [left, mid-1]
        }
        return left; // 或者 right+1
    }

    // 左闭右开区间写法
    int lower_bound2(vector<int> &nums, int target) {
        int left = 0, right = nums.size(); // 左闭右开区间 [left, right)
        while (left < right) { // 区间不为空
            // 循环不变量:
            // nums[left-1] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                left = mid + 1; // 范围缩小到 [mid+1, right)
            else
                right = mid; // 范围缩小到 [left, mid)
        }
        return left; // 或者 right
    }

    // 开区间写法
    int lower_bound3(vector<int> &nums, int target) {
        int left = -1, right = nums.size(); // 开区间 (left, right)
        while (left + 1 < right) { // 区间不为空
            // 循环不变量:
            // nums[left] < target
            // nums[right] >= target
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                left = mid; // 范围缩小到 (mid, right)
            else
                right = mid; // 范围缩小到 (left, mid)
        }
        return right; // 或者 left+1
    }

public:
    int search(vector<int> &nums, int target) {
        int i = lower_bound(nums, target); // 选择其中一种写法即可
        return i < nums.size() && nums[i] == target ? i : -1;
    }
};

作者:灵茶山艾府
链接:https://leetcode.cn/problems/binary-search/solutions/2023397/er-fen-cha-zhao-zong-shi-xie-bu-dui-yi-g-eplk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

69.x的平方根

题目力扣链接:给你一个非负整数 x ,计算并返回 x 的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

力扣官方题解:

class Solution {
public:
    int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long long)mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return ans;
    }
};

(1)在 C++ 中,`long long` 是一种整数类型,它表示的整数范围比 `int` 类型更大。具体来说,`long long` 是一种有符号整数类型,通常占用 8 个字节(64 位),它的取值范围是 `-9223372036854775808` 到 `9223372036854775807`。在这段代码中,将 `mid` 乘以 `mid` 后,使用 `long long` 来存储结果,以避免溢出。因为 `mid * mid` 的结果可能超出 `int` 类型的范围,为了确保计算的正确性,使用 `long long` 类型来存储结果。

3.移除元素(链接)

双指针法(快慢指针)判断快指针是否等于需要移除的元素val,不等于那么慢指针赋值为快指针的值,在遇到val之前快慢指针指向的是同一个位置,相当于不对数组进行操作。遇到val时,慢指针不动也不赋值,而快指针由于经历一个for循环往后移一位,当快指针再次遇到非val时才会赋值给慢指针,相当于把之前val位置的数用快指针遇到的非val数来依次覆盖。

代码随想录:

// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if (val != nums[fastIndex]) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};

删除重复项(力扣链接)

力扣官方题解:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        int fast = 1, slow = 1;
        while (fast < n) {
            if (nums[fast] != nums[fast - 1]) {
                nums[slow] = nums[fast];
                ++slow;
            }
            ++fast;
        }
        return slow;
    }
};

(1)在C++中,++slowslow++ 表示的含义是不同的。

  • ++slow 是前缀递增操作符,它会先将 slow 的值加1,然后返回递增后的值。所以,如果你写 ++slow,那么在表达式中,slow 将是递增后的值。
  • slow++ 是后缀递增操作符,它也会将 slow 的值加1,但是它会返回递增前的值。这意味着,如果你写 slow++,在表达式中,slow 将是递增前的值,然后才会执行递增操作。

举个例子:

int slow = 5; int result; result = ++slow; // 此时 result 和 slow 都是 6

在这个例子中,++slow 是先递增 slow 的值,然后将递增后的值赋给 result,所以 resultslow 都是 6。

int slow = 5; int result; result = slow++; // 此时 result 是 5,slow 是 6

在这个例子中,slow++ 是先将 slow 的值赋给 result,然后再递增 slow 的值,所以 result 是 5,而 slow 是 6。

844.比较含退格的字符串(力扣链接

(1)由于一个字符是否会被删掉,只取决于该字符后面的退格符,而与该字符前面的退格符无关。因此当我们逆序地遍历字符串,就可以立即确定当前字符是否会被删掉。

(2)这里是字符串所以用的是s.length()而不是nums.size()

(3)&& 如果两个操作数都非零,则条件为真;|| 如果两个操作数中有任意一个非零,则条件为真。

(4)思想:在while大循环里嵌套两个小while循环分别使两个数组从后往前比较,小循环中遇到#或者skip大于0(#造成的需要前移的数量)就会往前移一格,直到移到不是#并且skip为0跳出小循环,两字符串的小循环分别跳出后,即遇到了最后可以不删除保留下来的字符,再比较是否相等,遇到一个不相等就返回false。如果一个字符串移到-1(不存在)的位置时,也返回false。

4.有序数组的平方(链接

题目:给你一个按非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序排序。

思路:数组其实是有序的, 只不过负数平方之后可能成为最大数了。那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

(1)其中:for (int i = 0, j = A.size() - 1; i <= j;)在循环条件中,使用 i <= j 作为判断条件。这个条件的意思是,只要 i 指针不超过 j 指针,就可以继续循环。这样做是为了在遍历数组时,确保 i 指针不会越过 j 指针,从而保证了双指针的遍历范围是合法的。

5.长度最小的数组(链接)

题目:给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

滑动窗口法思想:滑动窗口的末尾位置用j表示,起始位置用i表示,j每往后移一位就让sum加上这一位的数值,如果sum大于目标值s,就计算子序列长度,更新一下最终子序列长度result,然sum减去i的数值,i++,再回到循环的开始来判断sum与s的关系。相当于是对于每一个j都要找到最短序列,找完以后j往后移一位,再找新的j对应的最短序列。

代码:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; // 滑动窗口数值之和
        int i = 0; // 滑动窗口起始位置
        int subLength = 0; // 滑动窗口的长度
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

6.螺旋矩阵(链接)

代码随想录采用的方法是每次一条边的最后一格不赋值,留给下一条边当起始位置。

力扣题解中找到一个简洁代码:这个代码每次一条边会把所有格赋值,下一条边再从下一格开始赋值。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        int t = 0;      // top
        int b = n-1;    // bottom
        int l = 0;      // left
        int r = n-1;    // right
        vector<vector<int>> ans(n,vector<int>(n));
        int k=1;
        while(k<=n*n){
            for(int i=l;i<=r;++i,++k) ans[t][i] = k;
            ++t;
            for(int i=t;i<=b;++i,++k) ans[i][r] = k;
            --r;
            for(int i=r;i>=l;--i,++k) ans[b][i] = k;
            --b;
            for(int i=b;i>=t;--i,++k) ans[i][l] = k;
            ++l;
        }
        return ans;
    }
};

(1)vector<vector<int>> ans(n, vector<int>(n));这行代码是在C++中创建一个二维向量(vector of vectors),名为 ans,其大小为 n×n,并且所有元素都被初始化为0。

  • vector<vector<int>>:这是一个嵌套的向量,表示包含多个向量的向量,即二维向量。
  • ans:这是向量的名称。
  • (n, vector<int>(n)):这是向量的初始化部分。在这里,vector<int>(n) 创建了一个大小为 n 的向量,其所有元素都初始化为0,然后 (n, ...) 使用拷贝构造函数初始化了 n 个这样的向量,最终构成了一个大小为 n×n 的二维向量。

因此,ans 是一个 n×n 的二维向量,其所有元素都被初始化为0。

(2)

for(int i=l;i<=r;++i,++k) ans[t][i] = k;

在C++中,for循环中逗号分隔的表达式执行顺序是从左到右依次执行的。在这种情况下:

  1. 首先,初始化语句 int i = l 会被执行,将 i 初始化为 l 的值。
  2. 接下来,循环条件 i <= r 会被检查,如果为真,则继续执行循环体;否则结束循环。
  3. 然后,循环体中的语句 ans[t][i] = k 会被执行,将 ans[t][i] 赋值为 k
  4. 最后,迭代表达式 ++i, ++k 会被执行,将 ik 同时递增。

因此,循环体中的语句 ans[t][i] = k 在每次迭代时都会被执行,而且 ik 都会在每次迭代后递增

在 C++ 中,数组和向量的索引都是从0开始的。因此,在二维向量 `ans` 中,`ans[t][i]` 中的 `i` 和 `t` 的起始点都是0。

链表

2.移除链表元素(链接)

题目:删除链表中等于给定值 val 的所有节点

思路:

  • 直接使用原来的链表分情况(头结点,非头结点)来进行删除操作。
  • 设置一个虚拟头结点在进行删除操作。
代码:
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) {
            if (cur->next->val == val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } else {
                cur = cur->next;
            }
        }
        return head;
    }
};

(1)ListNode* removeElements(ListNode* head, int val)

这个函数的名字是removeElements,它接受两个参数:一个是指向链表头部的指针 `head`,另一个是一个整数 `val`.函数的作用是移除链表中所有值为 `val` 的节点,并返回移除节点后的链表头部.`ListNode*` 表示这个函数返回一个指向 ListNode 类型的指针,即返回的是链表的头部指针。函数的实现会遍历链表,检查每个节点的值是否等于 `val`,如果是则删除该节点,直到遍历完整个链表为止。最后返回删除节点后的链表头部指针。

3.设计链表(链接)

题意:

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

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

    (1)struct LinkedNode{ int val; LinkedNode* next; LinkedNode(int val):val(val),next(nullptr){} };

    这段代码定义了一个名为 LinkedNode 的结构体,用于表示一个链表节点。

  • int val;:这是 LinkedNode 结构体中的一个成员变量,表示节点的值。

  • LinkedNode* next;:这是 LinkedNode 结构体中的另一个成员变量,表示指向下一个节点的指针。这样就可以通过 next 指针将链表中的节点连接起来。在这段代码中,LinkedNode* next;LinkedNode 结构体中的一个成员变量。它是一个指向 LinkedNode 类型的指针,用于指向链表中的下一个节点。这个指针使得链表节点可以彼此链接,从而形成一个链表结构。

  • 通过这个结构体,你可以创建表示链表节点的对象,并使用它们来构建链表数据结构。每个节点都包含一个值和一个指向下一个节点的指针,这样就可以形成一个链式结构。

  • LinkedNode(int val):val(val),next(nullptr){}:这是 LinkedNode 结构体的构造函数。它接受一个整数参数 val,用于初始化节点的值,并将 next 指针初始化为 nullptr,表示初始时没有下一个节点。

(2)构造函数是一种特殊的成员函数,它在创建类的对象时被自动调用,用于初始化对象的数据成员。在 C++ 中,构造函数的主要作用包括以下几个方面:

  1. 初始化对象的数据成员:构造函数可以在对象被创建时初始化对象的数据成员,确保对象在被使用之前处于一个合法的状态。这样可以避免对象中的数据成员未被初始化而导致的不确定行为。

  2. 分配资源:如果对象需要在创建时分配资源(如内存、文件句柄等),构造函数可以负责执行这些分配操作,并在对象被销毁时释放这些资源,以避免资源泄漏。

  3. 进行必要的初始化操作:构造函数可以执行一些必要的初始化操作,例如打开文件、建立网络连接、设置默认参数等。

  4. 实现重载:C++ 支持构造函数的重载,即可以定义多个构造函数,每个构造函数可以接受不同的参数列表。这样可以根据不同的需求选择合适的构造函数来创建对象。

LinkedNode(int val):val(val),next(nullptr){}中,构造函数 LinkedNode(int val) 负责初始化链表节点的值,并将指向下一个节点的指针初始化为 nullptr。这样,在创建链表节点对象时,可以直接提供节点的值作为参数,构造函数会负责将该值赋给节点的 val 成员,并将 next 指针初始化为空指针。

  • LinkedNode(int val): 这是构造函数的声明部分,它接受一个整数参数 val,用于初始化节点的值。构造函数在创建对象时被调用,用于初始化对象的成员变量。

  • : val(val): 这是成员初始化列表的一部分,用于将传入的参数 val 赋值给对象的成员变量 val。这里使用的是成员初始化列表的语法,等同于在构造函数体内写 this->val = val;,但是初始化列表的方式在性能上可能更高效,尤其对于某些类型的成员变量(如常量、引用和没有默认构造函数的成员变量)。

  • next(nullptr): 这是成员初始化列表的另一部分,用于将成员变量 next 初始化为 nullptrnullptr 是一个特殊的值,用于表示指针不指向任何对象。在这里,将 next 初始化为 nullptr,表示初始时该节点不链接到任何其他节点

当你作为一个小白自学Python时,以下是一些建议和步骤: 1. 学习编程基础知识:在开始学习Python之前,了解一些基本的编程概念和术语是很重要的。你可以学习一些基本的计算机科学概念,如变量、数据类型、条件语句、循环等。 2. 学习Python语法:Python是一种易于学习和理解的编程语言。你可以通过在线教程、视频教程或参考书籍来学习Python的语法规则和基本语句。掌握Python的基本语法是你进一步学习和开发的基础。 3. 练习编写代码:通过实践来巩固所学的知识是非常重要的。尝试编写一些简单的程序来解决问题,例如计算器、猜数字游戏等。这样可以帮助你熟悉Python的语法和逻辑。 4. 使用在线资源:互联网上有很多免费的资源可以帮助你学习Python。你可以参考一些优质的网站、博客、论坛和社区,如CSDN、Stack Overflow等。这些资源提供了大量的教程、示例代码和解答问题的平台。 5. 参与项目或实践:参与一些开源项目或实践项目可以帮助你更好地理解和应用Python。你可以加入一些开源社区,与其他开发者合作,共同开发项目。这样可以提高你的编程技能和经验。 6. 持续学习和提升:编程是一个不断学习和提升的过程。随着你的学习和实践,你会遇到更多的问题和挑战。不断学习新的知识,探索更深入的主题,参与更复杂的项目,可以帮助你不断提升自己的编程能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值