当前位置: 首页 > article >正文

数据结构-算法学习C++(入门)

目录

  • 03二进制和位运算
  • 04 选择、冒泡、插入排序
  • 05 对数器
  • 06 二分搜索
  • 07 时间复杂度和空间复杂度
  • 08 算法和数据结构
  • 09 单双链表
    • 09.1单双链表及反转
    • 09.2合并链表
    • 09.2两数相加
    • 09.2分隔链表
  • 013队列、栈、环形队列
    • 013.1队列
    • 013.2栈
    • 013.3循环队列
  • 014栈-队列的相互转换
    • 014.1用栈实现队列
    • 014.2用队列实现栈
  • 015最小栈
  • 016双端队列
  • 017二叉树实现
    • 017.1递归实现
      • 1、递归序
      • 2、先序
      • 3、中序
      • 4、后序
    • 017.2 非递归实现
    • 1.先序、中序
    • 2.后序

数据结构和算法-左神

03二进制和位运算

在这里插入图片描述

04 选择、冒泡、插入排序

// 交换数组中的两个元素
void swap(int arr[], int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}void printarr(int arr[], int n) {for (int i = 0; i < n; i++) {cout << arr[i] << " ";}cout << endl;
}// 选择排序
void selectionSort(int arr[], int n) {for (int i = 0; i < n - 1; i++) {int minIndex = i;for (int j = i + 1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}swap(arr, i, minIndex);}
}// 冒泡排序
void bubbleSort(int arr[], int n) {for (int i = 0; i < n - 1; i++) {for (int j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {swap(arr, j, j + 1);}}}
}// 插入排序
void insertionSort(int arr[], int n) {if (arr == nullptr || n < 2) {return;}for (int i = 1; i < n; i++) {for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {swap(arr, j, j + 1);// printarr(arr, n); // 打印当前数组状态}}
}

05 对数器

对数器:实验器,对与两种针对同一种问题的算法进行验证,以判断缩写代码是否正确(提出一易一难进行对比)

// 生成随机数组
vector<int> randomArray(int n, int v) {vector<int> arr(n);for (int i = 0; i < n; i++) {arr[i] = rand() % v + 1; // 生成 [1, v] 范围内的随机整数}return arr;
}// 复制数组
vector<int> copyArray(const vector<int>& arr) {return arr; // 直接返回一个副本
}// 比较两个数组是否相同
bool sameArray(const vector<int>& arr1, const vector<int>& arr2) {return arr1 == arr2; // 使用 vector 的比较运算符
}// 主函数
int main() {// 随机数组最大长度int N = 10;// 随机数组每个值,在1~V之间等概率随机int V = 10;// 测试次数int testTimes = 5;srand(time(0)); // 初始化随机数种子cout << "测试开始" << endl;for (int i = 0; i < testTimes; i++) {// 随机得到一个长度,长度在[0~N-1]int n = rand() % N;// 得到随机数组vector<int> arr = randomArray(n, V);vector<int> arr1 = copyArray(arr);vector<int> arr2 = copyArray(arr);vector<int> arr3 = copyArray(arr);// 转换为普通数组int* arr1_ptr = arr1.data();int* arr2_ptr = arr2.data();int* arr3_ptr = arr3.data();// 排序selectionSort(arr1_ptr, n);bubbleSort(arr2_ptr, n);insertionSort(arr3_ptr, n);// 比较结果if (!sameArray(arr1, arr2) || !sameArray(arr1, arr3)) {cout << "出错了!" << endl;// 打印出错的数组cout << "原始数组: ";for (int num : arr) {cout << num << " ";}cout << endl;cout << "选择排序结果: ";for (int num : arr1) {cout << num << " ";}cout << endl;cout << "冒泡排序结果: ";for (int num : arr2) {cout << num << " ";}cout << endl;cout << "插入排序结果: ";for (int num : arr3) {cout << num << " ";}cout << endl;return 1; // 退出程序}}cout << "测试结束" << endl;return 0;
}

上述是对三种排序算法的检测,如果报错可通过调整数组长度和数据大小,选择容易的数组进行测验,以解决报错

06 二分搜索

1)在有序数组中确定num存在还是不存在
2)在有序数组中找>=num的最左位置
3)在有序数组中找<=num的最右位置
4)二分搜索不一定发生在有序数组上(比如寻找峰值问题)
如果数组长度为n,那么二分搜索搜索次数是log n次,以2为底

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>using namespace std;// 生成随机数组
vector<int> randomArray(int n, int v) {vector<int> arr(n);for (int i = 0; i < n; i++) {arr[i] = rand() % v + 1; // 生成 [1, v] 范围内的随机整数}return arr;
}// 暴力解法:遍历数组查找数字
bool right(const vector<int>& sortedArr, int num) {for (int cur : sortedArr) {// 遍历数组if (cur == num) {return true;}}return false;
}// 二分查找:在有序数组(从小到大)中查找数字
bool exist(const vector<int>& arr, int num) {if (arr.empty()) {return false;}int l = 0, r = arr.size() - 1, m = 0;while (l <= r) {m = (l + r) / 2;//m=l+(r-l)/2; // 防止溢出if (arr[m] == num) {return true;} else if (arr[m] > num) {r = m - 1;} else {l = m + 1;}}return false;
}
int findleft(const vector<int>& arr, int num) {int l = 0, r = arr.size() - 1,m=0;int ans=-1;while (l <= r) {m = (l + r) / 2;if (arr[m] >= num) {ans=m; // 记录当前的左边界r = m - 1; // 继续向左查找} else {l = m + 1;}}return ans; // 返回左边界
}int findright(const vector<int>& arr, int num) {int l = 0, r = arr.size() - 1,m=0;int ans=-1;while (l <= r) {m = (l + r) / 2;if (arr[m] <= num) {ans=m; // 记录当前的右边界l = m + 1; // 继续向右查找} else {r = m - 1;}}return ans; // 返回右边界
}int findpeak(const vector<int>& arr) {int  n = arr.size() - 1;if(arr.size() == 0) {return -1; // 数组为空}if (arr[0] > arr[1]) {return 0; // 第一个元素是峰值}if (arr[n] > arr[n - 1]) {return n; // 最后一个元素是峰值}int l=1,r=n-1,m=0,ans=-1;while (l <= r) {m = (l + r) / 2;if (arr[m] < arr[m + 1]) {l = m + 1;} else if (arr[m] < arr[m - 1]) {r = m - 1;}else {ans = m; // 找到峰值break;}}return ans;
}// 主函数
int main() {// 随机数组最大长度int N = 100;// 随机数组每个值,在1~V之间等概率随机int V = 1000;// 测试次数int testTime = 500000;srand(time(0)); // 初始化随机数种子cout << "测试开始" << endl;for (int i = 0; i < testTime; i++) {// 随机得到一个长度,长度在[0~N-1]int n = rand() % N;// 得到随机数组vector<int> arr = randomArray(n, V);// 排序sort(arr.begin(), arr.end());// 随机生成一个数字int num = rand() % V + 1;// 比较暴力解法和二分查找的结果if (right(arr, num) != exist(arr, num)) {cout << "出错了!" << endl;// 打印出错的数组和数字cout << "数组: ";for (int x : arr) {cout << x << " ";}cout << endl;cout << "查找数字: " << num << endl;return 1; // 退出程序}}cout << "测试结束" << endl;return 0;
}

07 时间复杂度和空间复杂度

复杂度解释

时间复杂度:常数操作(固定时间的操作、执行时间和数据量无关)的次数,只关注最高阶项;针对固定流程,计算最差情况,对于随机行为,选择平均或者期望的时间复杂度;仅根据代码结构无法判断时间复杂度,需要通过算法流程进行判断。

08 算法和数据结构

硬计算类算法、软计算类算法:
硬计算类算法:精确求解。但是某些问题使用硬计算类的算法,可能会让计算的复杂度较高(大厂算法和数据结构笔试、面试题、acm比赛或者和acm形式类似的比赛,考察的都是硬计算类算法)
软计算类算法:更注重逼近解决问题,而不是精确求解。计算时间可控(比如:模糊逻辑、神经网络、进化计算、概率理论、混沌理论、支持向量机、群体智能)

硬计算类算法是所有程序员岗位都会考、任何写代码的工作都会用到的。前端、后端、架构、算法所有岗位都要用到。
但是算法工程师除了掌握硬计算类的算法之外,还需要掌握软计算类的算法

09 单双链表

09.1单双链表及反转

#include <iostream>
using namespace std;// 单链表节点
class ListNode {
public:int val;ListNode* next;// 构造函数:初始化节点值,下一个节点为 nullptrListNode(int val) : val(val), next(nullptr) {}// 构造函数初始化 val 和 next;或如下放在函数体里// ListNode(int val) {//     this->val = val; // 使用 this 指针访问成员变量//     this->next = nullptr;// }ListNode(int val, ListNode* next) : val(val), next(next) {}
};// 双链表节点
class DoubleListNode {
public:int value;DoubleListNode* last;DoubleListNode* next;DoubleListNode(int v) : value(v), last(nullptr), next(nullptr) {}
};// 反转单链表
static ListNode* reverseList(ListNode* head) {ListNode* pre = nullptr;ListNode* next = nullptr;while (head != nullptr) {next = head->next;head->next = pre;pre = head;head = next;}return pre;}// 反转双链表
static DoubleListNode* reverseDoubleList(DoubleListNode* head) {DoubleListNode* pre = nullptr;DoubleListNode* next = nullptr;while (head != nullptr) {next = head->next;head->next = pre;head->last = next;pre = head;head = next;}return pre;}// 打印链表
void printList(ListNode* head) {ListNode* current = head;while (current != nullptr) {cout << current->val << " -> ";current = current->next;}cout << "nullptr" << endl;
}// 主函数
int main() {// 创建链表 1 -> 2 -> 3 -> nullptrListNode* head = new ListNode(1);head->next = new ListNode(2);head->next->next = new ListNode(3);// 打印链表cout << "链表内容: ";printList(head);ListNode* reversedHead = reverseList(head);cout << "反转后的链表内容: ";printList(reversedHead);// 释放链表内存ListNode* current = reversedHead;while (current != nullptr) {ListNode* temp = current;current = current->next;delete temp;}return 0;
}

09.2合并链表

测试链接

#include <iostream>// 定义链表节点结构
struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode* next) : val(x), next(next) {}
};// 合并两个有序链表
ListNode* mergeTwoLists(ListNode* head1, ListNode* head2) {if (head1 == nullptr || head2 == nullptr) {return head1 == nullptr ? head2 : head1;}ListNode* head = head1->val <= head2->val ? head1 : head2;ListNode* cur1 = head->next;ListNode* cur2 = head == head1 ? head2 : head1;ListNode* pre = head;while (cur1 != nullptr && cur2 != nullptr) {if (cur1->val <= cur2->val) {pre->next = cur1;cur1 = cur1->next;} else {pre->next = cur2;cur2 = cur2->next;}pre = pre->next;}pre->next = cur1 != nullptr ? cur1 : cur2;return head;
}// 辅助函数:打印链表
void printList(ListNode* head) {while (head != nullptr) {std::cout << head->val << " -> ";head = head->next;}std::cout << "nullptr" << std::endl;
}int main() {// 创建两个链表ListNode* head1 = new ListNode(1, new ListNode(3, new ListNode(5)));ListNode* head2 = new ListNode(2, new ListNode(4, new ListNode(6)));std::cout << "List 1: ";printList(head1);std::cout << "List 2: ";printList(head2);// 合并链表ListNode* mergedHead = mergeTwoLists(head1, head2);std::cout << "Merged List: ";printList(mergedHead);// 释放链表内存(可选)while (mergedHead != nullptr) {ListNode* temp = mergedHead;mergedHead = mergedHead->next;delete temp;}return 0;
}

09.2两数相加

给你两个 非空 的链表,表示两个非负的整数
它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头

测试链接

#include <iostream>// 定义链表节点结构
struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode* next) : val(x), next(next) {}
};// 实现两个链表数字相加
ListNode* addTwoNumbers(ListNode* h1, ListNode* h2) {ListNode* ans = nullptr; // 用于存储结果链表的头节点ListNode* cur = nullptr; // 用于构建结果链表的当前节点int carry = 0; // 进位for (int sum, val; // 声明变量h1 != nullptr || h2 != nullptr; // 终止条件h1 = (h1 == nullptr ? nullptr : h1->next), // 每一步 h1 的跳转h2 = (h2 == nullptr ? nullptr : h2->next) // 每一步 h2 的跳转) {// 计算当前位的和,包括进位sum = (h1 == nullptr ? 0 : h1->val) + (h2 == nullptr ? 0 : h2->val) + carry;val = sum % 10; // 当前位的值carry = sum / 10; // 更新进位// 构建结果链表if (ans == nullptr) {ans = new ListNode(val);cur = ans;} else {cur->next = new ListNode(val);cur = cur->next;}}// 如果最后还有进位,追加一个新节点if (carry == 1) {cur->next = new ListNode(1);}return ans;
}// 辅助函数:打印链表
void printList(ListNode* head) {while (head != nullptr) {std::cout << head->val << " -> ";head = head->next;}std::cout << "nullptr" << std::endl;
}int main() {// 创建两个链表表示的数字ListNode* h1 = new ListNode(2, new ListNode(4, new ListNode(3))); // 表示数字 342ListNode* h2 = new ListNode(5, new ListNode(6, new ListNode(4))); // 表示数字 465std::cout << "List 1: ";printList(h1);std::cout << "List 2: ";printList(h2);// 计算两个链表数字的和ListNode* result = addTwoNumbers(h1, h2);std::cout << "Sum List: ";printList(result);// 释放链表内存(可选)while (h1 != nullptr) {ListNode* temp = h1;h1 = h1->next;delete temp;}while (h2 != nullptr) {ListNode* temp = h2;h2 = h2->next;delete temp;}while (result != nullptr) {ListNode* temp = result;result = result->next;delete temp;}return 0;
}

09.2分隔链表

给你一个链表的头节点 head 和一个特定值 x
请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置

测试链接

#include <iostream>// 定义链表节点结构
struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode* next) : val(x), next(next) {}
};// 实现链表分区操作
ListNode* partition(ListNode* head, int x) {ListNode* leftHead = nullptr; // < x 的区域ListNode* leftTail = nullptr;ListNode* rightHead = nullptr; // >= x 的区域ListNode* rightTail = nullptr;ListNode* next = nullptr;while (head != nullptr) {next = head->next; // 保存下一个节点head->next = nullptr; // 断开当前节点的连接if (head->val < x) {if (leftHead == nullptr) {leftHead = head;} else {leftTail->next = head;}leftTail = head;} else {if (rightHead == nullptr) {rightHead = head;} else {rightTail->next = head;}rightTail = head;}head = next; // 移动到下一个节点}if (leftHead == nullptr) {return rightHead; // 如果没有小于 x 的节点,直接返回右分区的头节点}// 将左分区的尾部连接到右分区的头部leftTail->next = rightHead;return leftHead; // 返回左分区的头节点
}// 辅助函数:打印链表
void printList(ListNode* head) {while (head != nullptr) {std::cout << head->val << " -> ";head = head->next;}std::cout << "nullptr" << std::endl;
}int main() {// 创建一个链表:1 -> 4 -> 3 -> 2 -> 5 -> 2ListNode* head = new ListNode(1, new ListNode(4, new ListNode(3, new ListNode(2, new ListNode(5, new ListNode(2))))));std::cout << "Original List: ";printList(head);// 分区操作,x = 3ListNode* partitionedHead = partition(head, 3);std::cout << "Partitioned List: ";printList(partitionedHead);// 释放链表内存(可选)while (partitionedHead != nullptr) {ListNode* temp = partitionedHead;partitionedHead = partitionedHead->next;delete temp;}return 0;
}

013队列、栈、环形队列

013.1队列

Queue1:使用queue容器进行

#include <queue>
#include <iostream>class Queue1 {
private:std::queue<int> queue; // 使用C++ STL中的queue容器public:// 判断队列是否为空bool isEmpty() {return queue.empty();}// 向队列中加入元素,加到队尾void offer(int num) {queue.push(num);}// 从队列中取出元素,从队头取出int poll() {if (queue.empty()) {throw std::out_of_range("Queue is empty"); // 如果队列为空,抛出异常}int front = queue.front(); // 获取队头元素queue.pop(); // 弹出队头元素return front;}// 返回队列头的元素,但不弹出int peek() {if (queue.empty()) {throw std::out_of_range("Queue is empty"); // 如果队列为空,抛出异常}return queue.front();}// 返回队列中元素的数量int size() {return queue.size();}
};int main() {Queue1 q;q.offer(1);q.offer(2);q.offer(3);std::cout << "Queue size: " << q.size() << std::endl; // 输出队列大小std::cout << "Front element: " << q.peek() << std::endl; // 输出队头元素std::cout << "Poll element: " << q.poll() << std::endl; // 弹出队头元素std::cout << "Queue size after poll: " << q.size() << std::endl; // 输出队列大小return 0;
}

queue2:使用数组,但是还是还是利用容器模拟数组

#include <iostream>
#include <vector>class Queue2 {
public:std::vector<int> queue;int l;int r;// 构造函数,初始化队列大小Queue2(int n) : queue(n, 0), l(0), r(0) {}// 判断队列是否为空bool isEmpty() {return l == r;}// 向队列中加入元素void offer(int num) {if (r >= queue.size()) {throw std::out_of_range("Queue is full"); // 如果队列已满,抛出异常}queue[r++] = num;}// 从队列中移除元素int poll() {if (isEmpty()) {throw std::out_of_range("Queue is empty"); // 如果队列为空,抛出异常}return queue[l++];}// 返回队列头部的元素int head() {if (isEmpty()) {throw std::out_of_range("Queue is empty"); // 如果队列为空,抛出异常}return queue[l];}// 返回队列尾部的元素int tail() {if (isEmpty()) {throw std::out_of_range("Queue is empty"); // 如果队列为空,抛出异常}return queue[r - 1];}// 返回队列中元素的数量int size() {return r - l;}
};int main() {Queue2 q(5); // 创建一个大小为5的队列q.offer(1);q.offer(2);q.offer(3);std::cout << "Queue size: " << q.size() << std::endl; // 输出队列大小std::cout << "Head element: " << q.head() << std::endl; // 输出队头元素std::cout << "Tail element: " << q.tail() << std::endl; // 输出队尾元素std::cout << "Poll element: " << q.poll() << std::endl; // 弹出队头元素std::cout << "Queue size after poll: " << q.size() << std::endl; // 输出队列大小return 0;
}

013.2栈

stack1:c++中stack容器

#include <iostream>
#include <stack>class Stack1 {
public:std::stack<int> stack;// 判断栈是否为空bool isEmpty() {return stack.empty();}// 向栈中压入一个元素void push(int num) {stack.push(num);}// 从栈中弹出一个元素int pop() {if (stack.empty()) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}int top = stack.top(); // 获取栈顶元素stack.pop(); // 弹出栈顶元素return top;}// 返回栈顶元素但不弹出int peek() {if (stack.empty()) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}return stack.top();}// 返回栈中元素的数量int size() {return stack.size();}
};int main() {Stack1 s;s.push(1);s.push(2);s.push(3);std::cout << "Stack size: " << s.size() << std::endl; // 输出栈大小std::cout << "Top element: " << s.peek() << std::endl; // 输出栈顶元素std::cout << "Pop element: " << s.pop() << std::endl; // 弹出栈顶元素std::cout << "Stack size after pop: " << s.size() << std::endl; // 输出栈大小return 0;
}

stack2:

#include <iostream>
#include <vector>
#include <stdexcept> // 用于抛出异常class Stack2 {
public:std::vector<int> stack; // 使用 std::vector 来模拟固定大小的数组int size; // 当前栈中的元素个数// 构造函数,初始化栈的大小Stack2(int n) : stack(n, 0), size(0) {}// 判断栈是否为空bool isEmpty() {return size == 0;}// 向栈中压入一个元素void push(int num) {if (size >= stack.size()) {throw std::out_of_range("Stack is full"); // 如果栈已满,抛出异常}stack[size++] = num;}// 从栈中弹出一个元素int pop() {if (isEmpty()) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}return stack[--size];}// 返回栈顶元素但不弹出int peek() {if (isEmpty()) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}return stack[size - 1];}// 返回栈中元素的数量int size() {return size;}
};int main() {Stack2 s(5); // 创建一个大小为5的栈s.push(1);s.push(2);s.push(3);std::cout << "Stack size: " << s.size() << std::endl; // 输出栈大小std::cout << "Top element: " << s.peek() << std::endl; // 输出栈顶元素std::cout << "Pop element: " << s.pop() << std::endl; // 弹出栈顶元素std::cout << "Stack size after pop: " << s.size() << std::endl; // 输出栈大小return 0;
}

013.3循环队列

#include <iostream>
#include <vector>class MyCircularQueue {
public:std::vector<int> queue; // 使用 std::vector 来模拟数组int l, r, size, limit;  // l: 队列头部指针,r: 队列尾部指针,size: 当前队列大小,limit: 队列容量// 构造函数,初始化循环队列的大小MyCircularQueue(int k) : queue(k, 0), l(0), r(0), size(0), limit(k) {}// 如果队列满了,什么也不做,返回false// 如果队列没满,加入value,返回truebool enQueue(int value) {if (isFull()) {return false;} else {queue[r] = value;// r = (r + 1) % limit; // 循环队列的关键操作:尾指针循环移动r=r==limit-1?0:(r+1);size++;return true;}}// 如果队列空了,什么也不做,返回false// 如果队列没空,弹出头部的数字,返回truebool deQueue() {if (isEmpty()) {return false;} else {// l = (l + 1) % limit; // 循环队列的关键操作:头指针循环移动l=l==limit-1?0:(l+1);size--;return true;}}// 返回队列头部的数字(不弹出),如果没有数返回-1int Front() {if (isEmpty()) {return -1;} else {return queue[l];}}// 返回队列尾部的数字(不弹出),如果没有数返回-1int Rear() {if (isEmpty()) {return -1;} else {int last = (r == 0) ? (limit - 1) : (r - 1); // 循环队列的关键操作:计算尾部索引return queue[last];}}// 判断队列是否为空bool isEmpty() {return size == 0;}// 判断队列是否已满bool isFull() {return size == limit;}
};int main() {MyCircularQueue q(5); // 创建一个大小为5的循环队列q.enQueue(1);q.enQueue(2);q.enQueue(3);std::cout << "Front element: " << q.Front() << std::endl; // 输出队头元素std::cout << "Rear element: " << q.Rear() << std::endl;  // 输出队尾元素std::cout << "Dequeue element: " << q.deQueue() << std::endl; // 弹出队头元素std::cout << "Front element after dequeue: " << q.Front() << std::endl; // 输出队头元素return 0;
}

014栈-队列的相互转换

014.1用栈实现队列

测试链接

#include <iostream>
#include <stack>class MyQueue {
public:std::stack<int> in;  // 用于存储新加入的元素std::stack<int> out; // 用于存储待弹出的元素MyQueue() {// 构造函数,初始化两个栈}// 从 in 栈倒入 out 栈void inToOut() {if (out.empty()) { // 只有当 out 栈为空时,才从 in 栈倒入数据while (!in.empty()) {out.push(in.top());in.pop();}}}// 向队列中加入元素void push(int x) {in.push(x); // 新元素直接压入 in 栈inToOut();  // 立即进行数据倒置,确保 out 栈始终是待弹出的顺序}// 从队列中弹出元素int pop() {inToOut(); // 确保 out 栈有数据int result = out.top(); // 获取 out 栈的栈顶元素out.pop(); // 弹出 out 栈的栈顶元素return result;}// 返回队列头部的元素(不弹出)int peek() {inToOut(); // 确保 out 栈有数据return out.top(); // 返回 out 栈的栈顶元素}// 判断队列是否为空bool empty() {return in.empty() && out.empty(); // 队列为空当且仅当两个栈都为空}
};int main() {MyQueue q;q.push(1);q.push(2);q.push(3);std::cout << "Front element: " << q.peek() << std::endl; // 输出队头元素std::cout << "Pop element: " << q.pop() << std::endl; // 弹出队头元素std::cout << "Front element after pop: " << q.peek() << std::endl; // 输出队头元素std::cout << "Queue is empty: " << (q.empty() ? "true" : "false") << std::endl; // 判断队列是否为空return 0;
}

014.2用队列实现栈

测试链接

#include <iostream>
#include <queue>class MyStack {
public:std::queue<int> queue;MyStack() {// 构造函数,初始化队列}// O(n) 时间复杂度void push(int x) {int n = queue.size();queue.push(x); // 将新元素加入队列for (int i = 0; i < n; i++) {queue.push(queue.front()); // 将队列头部元素移到队尾queue.pop(); // 移除队列头部元素}}int pop() {int result = queue.front(); // 获取队列头部元素queue.pop(); // 移除队列头部元素return result;}int top() {return queue.front(); // 返回队列头部元素}bool empty() {return queue.empty(); // 判断队列是否为空}
};int main() {MyStack stack;stack.push(1);stack.push(2);stack.push(3);std::cout << "Top element: " << stack.top() << std::endl; // 输出栈顶元素std::cout << "Pop element: " << stack.pop() << std::endl; // 弹出栈顶元素std::cout << "Top element after pop: " << stack.top() << std::endl; // 输出栈顶元素std::cout << "Stack is empty: " << (stack.empty() ? "true" : "false") << std::endl; // 判断栈是否为空return 0;
}

015最小栈

测试链接

minstack1:两个栈构成

#include <iostream>
#include <stack>
#include <stdexcept> // 用于抛出异常class MinStack {
public:std::stack<int> data; // 存储所有元素std::stack<int> min;  // 存储当前最小值MinStack() {// 构造函数,初始化两个栈}// 向栈中压入一个元素void push(int val) {data.push(val); // 将元素压入 data 栈if (min.empty() || val <= min.top()) {min.push(val); // 如果 min 栈为空或当前值小于等于 min 栈顶,则压入 min 栈} else {min.push(min.top()); // 否则,将 min 栈顶元素再次压入 min 栈}}// 从栈中弹出一个元素void pop() {if (data.empty()) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}data.pop(); // 弹出 data 栈顶元素min.pop();  // 弹出 min 栈顶元素}// 获取栈顶元素int top() {if (data.empty()) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}return data.top(); // 返回 data 栈顶元素}// 获取当前栈中的最小值int getMin() {if (min.empty()) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}return min.top(); // 返回 min 栈顶元素}
};int main() {MinStack stack;stack.push(3);stack.push(1);stack.push(2);std::cout << "Top element: " << stack.top() << std::endl; // 输出栈顶元素std::cout << "Minimum element: " << stack.getMin() << std::endl; // 输出当前最小值stack.pop();std::cout << "Top element after pop: " << stack.top() << std::endl; // 输出栈顶元素std::cout << "Minimum element after pop: " << stack.getMin() << std::endl; // 输出当前最小值return 0;
}

minstack2:数组构成

#include <iostream>
#include <stdexcept> // 用于抛出异常class MinStack {
public:static const int MAXN = 8001; // 最大容量int data[MAXN];  // 存储栈中的数据int min[MAXN];   // 存储当前栈中的最小值int size;        // 当前栈的大小MinStack() : size(0) {// 构造函数,初始化栈}// 向栈中压入一个元素void push(int val) {if (size >= MAXN) {throw std::out_of_range("Stack overflow"); // 如果栈已满,抛出异常}data[size] = val;if (size == 0 || val <= min[size - 1]) {min[size] = val;} else {min[size] = min[size - 1];}size++;}// 从栈中弹出一个元素void pop() {if (size == 0) {throw std::out_of_range("Stack underflow"); // 如果栈为空,抛出异常}size--;}// 获取栈顶元素int top() {if (size == 0) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}return data[size - 1];}// 获取当前栈中的最小值int getMin() {if (size == 0) {throw std::out_of_range("Stack is empty"); // 如果栈为空,抛出异常}return min[size - 1];}
};int main() {MinStack stack;stack.push(3);stack.push(1);stack.push(2);std::cout << "Top element: " << stack.top() << std::endl; // 输出栈顶元素std::cout << "Minimum element: " << stack.getMin() << std::endl; // 输出当前最小值stack.pop();std::cout << "Top element after pop: " << stack.top() << std::endl; // 输出栈顶元素std::cout << "Minimum element after pop: " << stack.getMin() << std::endl; // 输出当前最小值return 0;
}

016双端队列

测试链接

  • 使用deque容器
#include <iostream>
#include <deque>class MyCircularDeque {
public:std::deque<int> deque; // 使用 std::deque 作为底层数据结构int size;              // 当前队列的大小int limit;             // 队列的最大容量// 构造函数,初始化队列的最大容量MyCircularDeque(int k) : size(0), limit(k) {}// 在队列前端插入一个元素bool insertFront(int value) {if (isFull()) {return false; // 如果队列已满,返回 false} else {deque.push_front(value); // 在前端插入元素size++;return true;}}// 在队列后端插入一个元素bool insertLast(int value) {if (isFull()) {return false; // 如果队列已满,返回 false} else {deque.push_back(value); // 在后端插入元素size++;return true;}}// 从队列前端删除一个元素bool deleteFront() {if (isEmpty()) {return false; // 如果队列为空,返回 false} else {deque.pop_front(); // 从前端删除元素size--;return true;}}// 从队列后端删除一个元素bool deleteLast() {if (isEmpty()) {return false; // 如果队列为空,返回 false} else {deque.pop_back(); // 从后端删除元素size--;return true;}}// 获取队列前端的元素int getFront() {if (isEmpty()) {return -1; // 如果队列为空,返回 -1} else {return deque.front(); // 返回前端元素}}// 获取队列后端的元素int getRear() {if (isEmpty()) {return -1; // 如果队列为空,返回 -1} else {return deque.back(); // 返回后端元素}}// 判断队列是否为空bool isEmpty() {return size == 0;}// 判断队列是否已满bool isFull() {return size == limit;}
};int main() {MyCircularDeque deque(5); // 创建一个容量为 5 的循环双端队列deque.insertFront(1);deque.insertLast(2);deque.insertFront(3);deque.insertLast(4);std::cout << "Front element: " << deque.getFront() << std::endl; // 输出前端元素std::cout << "Rear element: " << deque.getRear() << std::endl;   // 输出后端元素deque.deleteFront();deque.deleteLast();std::cout << "Front element after delete: " << deque.getFront() << std::endl; // 输出前端元素std::cout << "Rear element after delete: " << deque.getRear() << std::endl;   // 输出后端元素return 0;
}
  • 使用数组
#include <iostream>
#include <vector>class MyCircularDeque {
public:std::vector<int> deque; // 使用 std::vector 作为底层数组int l, r, size, limit;  // l: 队列前端指针,r: 队列后端指针,size: 当前大小,limit: 最大容量// 构造函数,初始化队列MyCircularDeque(int k) : deque(k), l(0), r(0), size(0), limit(k) {}// 在队列前端插入一个元素bool insertFront(int value) {if (isFull()) {return false; // 如果队列已满,返回 false}if (isEmpty()) {l = r = 0; // 如果队列为空,初始化指针} else {l = (l == 0) ? (limit - 1) : (l - 1); // 循环移动前端指针}deque[l] = value; // 插入元素size++;return true;}// 在队列后端插入一个元素bool insertLast(int value) {if (isFull()) {return false; // 如果队列已满,返回 false}if (isEmpty()) {l = r = 0; // 如果队列为空,初始化指针} else {r = (r == limit - 1) ? 0 : (r + 1); // 循环移动后端指针}deque[r] = value; // 插入元素size++;return true;}// 从队列前端删除一个元素bool deleteFront() {if (isEmpty()) {return false; // 如果队列为空,返回 false}l = (l == limit - 1) ? 0 : (l + 1); // 循环移动前端指针size--;return true;}// 从队列后端删除一个元素bool deleteLast() {if (isEmpty()) {return false; // 如果队列为空,返回 false}r = (r == 0) ? (limit - 1) : (r - 1); // 循环移动后端指针size--;return true;}// 获取队列前端的元素int getFront() {if (isEmpty()) {return -1; // 如果队列为空,返回 -1}return deque[l]; // 返回前端元素}// 获取队列后端的元素int getRear() {if (isEmpty()) {return -1; // 如果队列为空,返回 -1}return deque[r]; // 返回后端元素}// 判断队列是否为空bool isEmpty() {return size == 0;}// 判断队列是否已满bool isFull() {return size == limit;}
};int main() {MyCircularDeque deque(5); // 创建一个容量为 5 的循环双端队列deque.insertFront(1);deque.insertLast(2);deque.insertFront(3);deque.insertLast(4);std::cout << "Front element: " << deque.getFront() << std::endl; // 输出前端元素std::cout << "Rear element: " << deque.getRear() << std::endl;   // 输出后端元素deque.deleteFront();deque.deleteLast();std::cout << "Front element after delete: " << deque.getFront() << std::endl; // 输出前端元素std::cout << "Rear element after delete: " << deque.getRear() << std::endl;   // 输出后端元素return 0;
}

017二叉树实现

先序:任何子树先中后左再右
中序:左中右
后序:左右中

017.1递归实现

1、递归序

#include <iostream>// 定义二叉树节点结构
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int v) : val(v), left(nullptr), right(nullptr) {}
};// 递归函数,用于遍历二叉树
void f(TreeNode* head) {if (head == nullptr) {return;}// 1:第一次到所在节点f(head->left); // 递归遍历左子树// 2:第二次到所在节点f(head->right); // 递归遍历右子树// 3:第三次到所在节点
}// 辅助函数:创建一个简单的二叉树
TreeNode* createTree() {TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);root->right->left = new TreeNode(6);root->right->right = new TreeNode(7);return root;
}// 辅助函数:释放二叉树内存
void deleteTree(TreeNode* root) {if (root == nullptr) {return;}deleteTree(root->left);deleteTree(root->right);delete root;
}

在这里插入图片描述
按照递归序,上述顺序为:1,2,4,4,4,2,5,5,5,2,1,3,6,6,6,3,7,7,7,3,1;可以看出在每个节点都经过三次。之后的先序、中序、后序可以看作在递归序中的三次停靠分别打印所在节点。

时间复杂度O(n),额外空间复杂度O(h),h是二叉树的高度;

2、先序

// 前序遍历:递归版
void preOrder(TreeNode* head) {if (head == nullptr) {return;}std::cout << head->val << " "; // 访问当前节点preOrder(head->left);          // 递归遍历左子树preOrder(head->right);         // 递归遍历右子树
}

3、中序

// 中序遍历:递归版
void inOrder(TreeNode* head) {if (head == nullptr) {return;}inOrder(head->left);           // 递归遍历左子树std::cout << head->val << " "; // 访问当前节点inOrder(head->right);          // 递归遍历右子树
}

4、后序

// 后序遍历:递归版
void posOrder(TreeNode* head) {if (head == nullptr) {return;}posOrder(head->left);          // 递归遍历左子树posOrder(head->right);         // 递归遍历右子树std::cout << head->val << " "; // 访问当前节点
}

017.2 非递归实现

先序测试链接
中序测试链接

1.先序、中序

#include <iostream>
#include <stack>// 定义二叉树节点结构
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int v) : val(v), left(nullptr), right(nullptr) {}
};// 先序遍历:非递归版
void preOrder(TreeNode* head) {if (head != nullptr) {std::stack<TreeNode*> stack; // 使用 std::stack 来模拟递归stack.push(head);while (!stack.empty()) {head = stack.top(); // 获取栈顶元素stack.pop();        // 弹出栈顶元素std::cout << head->val << " "; // 访问当前节点// 先将右子节点入栈(如果存在)if (head->right != nullptr) {stack.push(head->right);}// 再将左子节点入栈(如果存在)if (head->left != nullptr) {stack.push(head->left);}}std::cout << std::endl;}
}// 中序遍历:非递归版
void inOrder(TreeNode* head) {if (head != nullptr) {std::stack<TreeNode*> stack; // 使用 std::stack 来模拟递归while (!stack.empty() || head != nullptr) {// 将当前节点的所有左子节点压入栈while (head != nullptr) {stack.push(head);head = head->left;}// 弹出栈顶节点并访问head = stack.top();stack.pop();std::cout << head->val << " ";// 转向右子节点head = head->right;}std::cout << std::endl;}
}// 辅助函数:创建一个简单的二叉树
TreeNode* createTree() {TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);root->right->left = new TreeNode(6);root->right->right = new TreeNode(7);return root;
}// 辅助函数:释放二叉树内存
void deleteTree(TreeNode* root) {if (root == nullptr) {return;}deleteTree(root->left);deleteTree(root->right);delete root;
}int main() {TreeNode* root = createTree(); // 创建一个简单的二叉树std::cout << "PreOrder (Non-Recursive): ";preOrder(root); // 非递归先序遍历std::cout << "inOrder (Non-Recursive): ";inOrder(root); // 非递归先序遍历deleteTree(root); // 释放二叉树内存return 0;
}

2.后序

测试链接

  • 使用两个栈
#include <iostream>
#include <stack>struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int v) : val(v), left(nullptr), right(nullptr) {}
};void posOrderTwoStacks(TreeNode* head) {if (head != nullptr) {std::stack<TreeNode*> stack; // 用于模拟递归std::stack<TreeNode*> collect; // 用于收集节点stack.push(head);while (!stack.empty()) {head = stack.top();stack.pop();collect.push(head);if (head->left != nullptr) {stack.push(head->left);}if (head->right != nullptr) {stack.push(head->right);}}while (!collect.empty()) {std::cout << collect.top()->val << " ";collect.pop();}std::cout << std::endl;}
}
  • 使用一个栈
void posOrderOneStack(TreeNode* h) {if (h != nullptr) {std::stack<TreeNode*> stack;stack.push(h);TreeNode* lastPrinted = nullptr; // 上一次打印的节点while (!stack.empty()) {TreeNode* cur = stack.top();if (cur->left != nullptr && lastPrinted != cur->left && lastPrinted != cur->right) {// 有左子树且左子树未处理stack.push(cur->left);} else if (cur->right != nullptr && lastPrinted != cur->right) {// 有右子树且右子树未处理stack.push(cur->right);} else {// 左子树和右子树都已处理或不存在std::cout << cur->val << " ";lastPrinted = stack.top();stack.pop();}}std::cout << std::endl;}
}

相关文章:

数据结构-算法学习C++(入门)

目录 03二进制和位运算04 选择、冒泡、插入排序05 对数器06 二分搜索07 时间复杂度和空间复杂度08 算法和数据结构09 单双链表09.1单双链表及反转09.2合并链表09.2两数相加09.2分隔链表 013队列、栈、环形队列013.1队列013.2栈013.3循环队列 014栈-队列的相互转换014.1用栈实现…...

访谈 | 吴恩达全景解读 AI Agents 发展现状:多智能体、工具生态、评估体系、语音栈、Vibe Coding 及创业建议一文尽览

在最新的 LangChain Interrupt 大会上&#xff08;2025&#xff09;&#xff0c;LangChain 联合创始人 & CEO Harrison Chase 与吴恩达&#xff08;Andrew Ng&#xff09;就 AI Agnets 的发展现状&#xff0c;进行了一场炉边谈话。 吴恩达回顾了与 LangChain 的渊源&#…...

连接关键点:使用 ES|QL 联接实现更丰富的可观测性洞察

作者&#xff1a;来自 Elastic Luca Wintergerst ES|QL 的 LOOKUP JOIN 现已进入技术预览阶段&#xff0c;它允许你在查询时对日志、指标和追踪进行丰富处理&#xff0c;无需在摄取时进行非规范化。动态添加部署、基础设施或业务上下文&#xff0c;减少存储占用&#xff0c;加速…...

Tiktok App 登录账号、密码、验证码 XOR 加密算法

抖音 App 登录账号、密码、验证码 XOR 加密算法% E9 n z, \& R1 a4 b. ^ 流程分析 登录 Tiktok APP 时&#xff0c;通过抓包发现账号密码是非明文传输的。 <?php// http://xxx.xx.x.x.x/tiktok/$tiktok new TikTokClient();$userId 7212597544604484614; $secUid …...

Flask + Celery 应用

目录 Flask Celery 应用项目结构1. 创建app.py2. 创建tasks.py3. 创建celery_worker.py4. 创建templates目录和index.html运行应用测试文件 Flask Celery 应用 对于Flask与Celery结合的例子&#xff0c;需要创建几个文件。首先安装必要的依赖&#xff1a; pip install flas…...

奥威BI+AI数据分析:企业数智化转型的加速器

在当今数据驱动的时代&#xff0c;企业对于数据分析的需求日益增长。奥威BIAI数据分析的组合&#xff0c;正成为众多企业数智化转型的加速器。 奥威BI以其强大的数据处理和可视化能力著称。它能够轻松接入多种数据源&#xff0c;实现数据的快速整合与清洗。通过内置的ETL工具&…...

python打卡day43

复习日 作业&#xff1a; kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 找了个街头食物图像分类的数据集Popular Street Foods&#xff08;其实写代码的时候就开始后悔了&#xff09;&#xff0c;原因在于&…...

MySQL 如何判断某个表中是否存在某个字段

在MySQL中&#xff0c;判断某个表中是否存在某个字段&#xff0c;可以通过查询系统数据库 INFORMATION_SCHEMA.COLUMNS 实现。以下是详细步骤和示例&#xff1a; 方法&#xff1a;使用 INFORMATION_SCHEMA.COLUMNS 通过查询系统元数据表 COLUMNS&#xff0c;检查目标字段是否存…...

Linux --进程优先级

概念 什么是进程优先级&#xff0c;为什么需要进程优先级&#xff0c;怎么做到进程优先级这是本文需要解释清楚的。 优先级的本质其实就是排队&#xff0c;为了去争夺有限的资源&#xff0c;比如cpu的调度。cpu资源分配的先后性就是指进程的优先级。优先级高的进程有优先执行的…...

安装和配置 Nginx 和 Mysql —— 一步一步配置 Ubuntu Server 的 NodeJS 服务器详细实录6

前言 昨天更新了四篇博客&#xff0c;我们顺利的 安装了 ubuntu server 服务器&#xff0c;并且配置好了 ssh 免密登录服务器&#xff0c;安装好了 服务器常用软件安装, 配置好了 zsh 和 vim 以及 通过 NVM 安装好Nodejs&#xff0c;还有PNPM包管理工具 。 作为服务器的运行…...

Linux 测试本机与192.168.1.130 主机161/udp端口连通性

Linux 测试本机与 192.168.1.130 主机 161/UDP 端口连通性 161/UDP 端口是 SNMP&#xff08;简单网络管理协议&#xff09;的标准端口。以下是多种测试方法&#xff1a; &#x1f6e0;️ 1. 使用 nmap 进行专业测试&#xff08;推荐&#xff09; sudo nmap -sU -p 161 -Pn 1…...

OpenCV 滑动条调整图像亮度

一、知识点 1、int createTrackbar(const String & trackbarname, const String & winname, int * value, int count, TrackbarCallback onChange 0, void * userdata 0); (1)、创建一个滑动条并将其附在指定窗口上。 (2)、参数说明: trackbarname: 创建的…...

图解gpt之注意力机制原理与应用

大家有没有注意到&#xff0c;当序列变长时&#xff0c;比如翻译一篇长文章&#xff0c;或者处理一个长句子&#xff0c;RNN这种编码器就有点力不从心了。它把整个序列信息压缩到一个固定大小的向量里&#xff0c;信息丢失严重&#xff0c;而且很难记住前面的细节&#xff0c;特…...

硬件学习笔记--65 MCU的RAM及FLash简介

MCU&#xff08;微控制器单元&#xff09;内部的 RAM 和 Flash 是最关键的两种存储器&#xff0c;它们直接影响MCU的性能、功耗和编程方式。以下是它们的详细讲解及作用&#xff1a; 1. RAM&#xff08;随机存取存储器&#xff09; 1.1 特性 1&#xff09;易失性&#xff1a…...

【Oracle】视图

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 视图基础概述1.1 视图的概念与特点1.2 视图的工作原理1.3 视图的分类 2. 简单视图2.1 创建简单视图2.1.1 基本简单视图2.1.2 带计算列的简单视图 2.2 简单视图的DML操作2.2.1 通过视图进行INSERT操作2.2.2 通…...

数据库 MongoDB (NoSQL) 与 MySQL (SQL) 的写法对比

MongoDB (NoSQL) 与 MySQL (SQL) 的写法对比及优劣势分析 基本概念差异 MySQL/SQL&#xff1a;关系型数据库&#xff0c;使用结构化查询语言(SQL)&#xff0c;数据以表格形式存储&#xff0c;有预定义的模式(schema)MongoDB/NoSQL&#xff1a;文档型数据库&#xff0c;无固定…...

基于粒子滤波的PSK信号解调实现

基于粒子滤波的PSK信号解调实现 一、引言 相移键控(PSK)是数字通信中广泛应用的调制技术。在非高斯噪声和动态相位偏移环境下,传统锁相环(PLL)性能受限。粒子滤波(Particle Filter)作为一种序列蒙特卡洛方法,能有效处理非线性/非高斯系统的状态估计问题。本文将详细阐…...

更强劲,更高效:智源研究院开源轻量级超长视频理解模型Video-XL-2

长视频理解是多模态大模型关键能力之一。尽管OpenAI GPT-4o、Google Gemini等私有模型已在该领域取得显著进展&#xff0c;当前的开源模型在效果、计算开销和运行效率等方面仍存在明显短板。近日&#xff0c;智源研究院联合上海交通大学等机构&#xff0c;正式发布新一代超长视…...

2025.6.3学习日记 Nginx 基本概念 配置 指令 文件

1.初始nginx Nginx&#xff08;发音为 “engine x”&#xff09;是一款高性能的开源 Web 服务器软件&#xff0c;同时也具备反向代理、负载均衡、邮件代理等功能。它由俄罗斯工程师 Igor Sysoev 开发&#xff0c;最初用于解决高并发场景下的性能问题&#xff0c;因其轻量级、高…...

【连接器专题】案例:产品测试顺序表解读与应用

在查看SD卡座连接器的规格书,一些测试报告时,你可能会看到如下一张产品测试顺序表。为什么会出现一张测试顺序表呢? 测试顺序表的使用其实定义测试环节的验证的“路线图”和“游戏规则”,本文就以我人个经验带领大家一起看懂这张表并理解其设计逻辑。 测试顺序表结构 测试…...

星动纪元的机器人大模型 VPP,泛化能力效果如何?与 VLA 技术的区别是什么?

点击上方关注 “终端研发部” 设为“星标”&#xff0c;和你一起掌握更多数据库知识 VPP 利用了大量互联网视频数据进行训练&#xff0c;直接学习人类动作&#xff0c;减轻了对于高质量机器人真机数据的依赖&#xff0c;且可在不同人形机器人本体之间自如切换&#xff0c;这有望…...

4000万日订单背后,饿了么再掀即时零售的“效率革命”

当即时零售转向价值深耕&#xff0c;赢面就是综合实力的强弱。 文&#xff5c;郭梦仪 编&#xff5c;王一粟 在硝烟弥漫的外卖行业“三国杀”中&#xff0c;饿了么与淘宝闪购的日订单量竟然突破了4000万单。 而距淘宝闪购正式上线&#xff0c;还不到一个月。 在大额福利优惠…...

入门AJAX——XMLHttpRequest(Get)

一、什么是 AJAX AJAX Asynchronous JavaScript And XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 1、XML与异步JS XML: 是一种比较老的前后端数据传输格式&#xff08;已经几乎被 JSON 代替&#xff09;。它的格式与HTML类似&#xff0c;通过严格的闭合自定义标…...

5分钟申请edu邮箱【方案本周有效】

这篇文章主要展示的是成果。如果你是第1次看见我的内容&#xff0c;具体的步骤请翻看往期的两篇作品。先看更正补全&#xff0c;再看下一个。 建议你边看边操作。 【更正补全】edu教育申请通过方案 本周 edu教育邮箱注册可行方案 #edu邮箱 伟大无需多言 我已经验证了四个了…...

闲谈PMIC和SBC

今天不卷&#xff0c;简单写点。 在ECU设计里&#xff0c;供电芯片选型是逃不开的话题&#xff0c;所以聊聊PMIC或者SBC的各自特点&#xff0c;小小总结下。 PMIC&#xff0c;全称Power Management Intergrated Circuits&#xff0c;听名字就很专业&#xff1a;电源管理&…...

Java垃圾回收机制深度解析:从理论到实践的全方位指南

Java垃圾回收(GC)是Java虚拟机(JVM)的核心功能&#xff0c;它自动管理内存分配与回收&#xff0c;避免了C/C中常见的内存泄漏问题。本文将深入剖析Java垃圾回收的工作原理、算法实现、收集器类型及调优策略&#xff0c;助你全面掌握JVM内存管理的精髓。 一、垃圾回收基础概念 …...

Ubuntu系统 | 本地部署ollama+deepseek

1、Ollama介绍 Ollama是由Llama开发团队推出的开源项目,旨在为用户提供高效、灵活的本地化大型语言模型(LLM)运行环境。作为Llama系列模型的重要配套工具,Ollama解决了传统云服务对计算资源和网络连接的依赖问题,让用户能够在个人电脑或私有服务器上部署和运行如Llama 3等…...

论文阅读:CLIP:Learning Transferable Visual Models From Natural Language Supervision

从自然语言监督中学习可迁移的视觉模型 虽然有点data/gpu is all you need的味道&#xff0c;但是整体实验和谈论丰富度上还是很多的&#xff0c;也是一篇让我多次想放弃的文章&#xff0c;因为真的是非常长的原文和超级多的实验讨论&#xff0c;隔着屏幕感受到了实验的工作量之…...

在图像分析算法部署中应对流行趋势的变化|文献速递-深度学习医疗AI最新文献

Title 题目 Navigating prevalence shifts in image analysis algorithm deployment 在图像分析算法部署中应对流行趋势的变化 01 文献速递介绍 机器学习&#xff08;ML&#xff09;已开始革新成像研究与实践的诸多领域。然而&#xff0c;医学图像分析领域存在显著的转化鸿…...

CAMEL-AI开源自动化任务执行助手OWL一键整合包下载

OWL 是由 CAMEL-AI 团队开发的开源多智能体协作框架&#xff0c;旨在通过动态智能体交互实现复杂任务的自动化处理&#xff0c;在 GAIA 基准测试中以 69.09 分位列开源框架榜首&#xff0c;被誉为“Manus 的开源平替”。我基于当前最新版本制作了免安装一键启动整合包。 CAMEL-…...