算法四 习题 1.3

数组实现栈

#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;class MyStack {
private:vector<int> data;  // 用于存储栈元素的数组public:// 构造函数MyStack() {}// 入栈操作void push(int val) {data.push_back(val);  // 在数组末尾添加元素}// 出栈操作void pop() {if (empty()) {throw runtime_error("Stack underflow");}data.pop_back();  // 移除数组末尾元素}// 获取栈顶元素int top() {if (empty()) {throw runtime_error("Stack is empty");}return data.back();  // 返回数组末尾元素}// 检查栈是否为空bool empty() const {return data.empty();}// 返回栈中的元素数量int size() const {return data.size();}
};// 测试程序
int main() {return 0;
}

链表实现栈

#include <iostream>
#include <stdexcept>
using namespace std;// 链表节点结构
class Node {
public:int data;Node* next;// 构造函数Node(int val) : data(val), next(nullptr) {}
};// 使用链表实现的栈
class LinkedListStack {
private:Node* top_ptr;  // 指向栈顶的指针int n;          // 栈中元素的数量public:// 构造函数LinkedListStack() : top_ptr(nullptr), n(0) {}// 析构函数,释放所有节点~LinkedListStack() {while (!empty()) {pop();}}// 入栈操作void push(int val) {Node* new_node = new Node(val);new_node->next = top_ptr;top_ptr = new_node;n++;}// 出栈操作void pop() {if (empty()) {throw runtime_error("Stack underflow");}Node* temp = top_ptr;top_ptr = top_ptr->next;delete temp;n--;}// 获取栈顶元素int top() {if (empty()) {throw runtime_error("Stack is empty");}return top_ptr->data;}// 检查栈是否为空bool empty() const {return top_ptr == nullptr;}// 返回栈中的元素数量int size() const {return n;}// 打印栈中的所有元素(用于调试)void printStack() const {if (empty()) {cout << "Stack is empty" << endl;return;}cout << "Stack (top to bottom): ";Node* current = top_ptr;while (current != nullptr) {cout << current->data << " ";current = current->next;}cout << endl;}
};// 测试程序
int main() {return 0;
}

双向队列和栈

#include <iostream>
#include <stdexcept>
using namespace std;// 双向链表节点结构
class Node {
public:int data;Node* next;Node* prev;// 构造函数Node(int val) : data(val), next(nullptr), prev(nullptr) {}
};// 使用双向链表实现的双向队列
class Deque {
private:Node* front;  // 指向队列前端的指针Node* back;   // 指向队列后端的指针int n;        // 队列中元素的数量public:// 构造函数Deque() : front(nullptr), back(nullptr), n(0) {}// 析构函数,释放所有节点~Deque() {while (!empty()) {removeFront();}}// 检查队列是否为空bool empty() const {return n == 0;}// 返回队列中的元素数量int size() const {return n;}// 在队列前端添加元素void addFront(int val) {Node* new_node = new Node(val);if (empty()) {front = back = new_node;} else {new_node->next = front;front->prev = new_node;front = new_node;}n++;}// 在队列后端添加元素void addBack(int val) {Node* new_node = new Node(val);if (empty()) {front = back = new_node;} else {new_node->prev = back;back->next = new_node;back = new_node;}n++;}// 从队列前端移除元素int removeFront() {if (empty()) {throw runtime_error("Deque underflow");}Node* temp = front;int val = temp->data;if (front == back) {// 队列中只有一个元素front = back = nullptr;} else {front = front->next;front->prev = nullptr;}delete temp;n--;return val;}// 从队列后端移除元素int removeBack() {if (empty()) {throw runtime_error("Deque underflow");}Node* temp = back;int val = temp->data;if (front == back) {// 队列中只有一个元素front = back = nullptr;} else {back = back->prev;back->next = nullptr;}delete temp;n--;return val;}// 获取队列前端元素int peekFront() const {if (empty()) {throw runtime_error("Deque is empty");}return front->data;}// 获取队列后端元素int peekBack() const {if (empty()) {throw runtime_error("Deque is empty");}return back->data;}// 打印队列中的所有元素(用于调试)void printDeque() const {if (empty()) {cout << "Deque is empty" << endl;return;}cout << "Deque (front to back): ";Node* current = front;while (current != nullptr) {cout << current->data << " ";current = current->next;}cout << endl;}
};// 使用双向队列实现的栈
class DequeStack {
private:Deque deque;  // 使用双向队列作为底层数据结构public:// 入栈操作(在队列前端添加元素)void push(int val) {deque.addFront(val);}// 出栈操作(从队列前端移除元素)int pop() {return deque.removeFront();}// 获取栈顶元素int top() const {return deque.peekFront();}// 检查栈是否为空bool empty() const {return deque.empty();}// 返回栈中的元素数量int size() const {return deque.size();}// 打印栈中的所有元素(用于调试)void printStack() const {cout << "Stack (via Deque): ";deque.printDeque();}
};// 使用双向队列实现的队列
class DequeQueue {
private:Deque deque;  // 使用双向队列作为底层数据结构public:// 入队操作(在队列后端添加元素)void enqueue(int val) {deque.addBack(val);}// 出队操作(从队列前端移除元素)int dequeue() {return deque.removeFront();}// 获取队头元素int front() const {return deque.peekFront();}// 检查队列是否为空bool empty() const {return deque.empty();}// 返回队列中的元素数量int size() const {return deque.size();}// 打印队列中的所有元素(用于调试)void printQueue() const {cout << "Queue (via Deque): ";deque.printDeque();}
};// 测试程序
int main() {cout << "===== Testing Deque =====" << endl;Deque deque;deque.addFront(10);deque.printDeque();deque.addBack(20);deque.printDeque();deque.addFront(5);deque.printDeque();deque.addBack(30);deque.printDeque();cout << "Front element: " << deque.peekFront() << endl;cout << "Back element: " << deque.peekBack() << endl;cout << "Removing front: " << deque.removeFront() << endl;deque.printDeque();cout << "Removing back: " << deque.removeBack() << endl;deque.printDeque();cout << "\n===== Testing Stack implemented with Deque =====" << endl;DequeStack stack;stack.push(10);stack.push(20);stack.push(30);stack.printStack();cout << "Top element: " << stack.top() << endl;cout << "Popping: " << stack.pop() << endl;stack.printStack();cout << "\n===== Testing Queue implemented with Deque =====" << endl;DequeQueue queue;queue.enqueue(10);queue.enqueue(20);queue.enqueue(30);queue.printQueue();cout << "Front element: " << queue.front() << endl;cout << "Dequeuing: " << queue.dequeue() << endl;queue.printQueue();return 0;
}

栈与队列

#include <iostream>
#include <stack>
#include <queue>
#include <stdexcept>
using namespace std;// 使用两个栈实现队列
class StackQueue {
private:stack<int> inbox;   // 用于入队操作的栈stack<int> outbox;  // 用于出队操作的栈// 将元素从inbox转移到outboxvoid transfer() {// 只有当outbox为空时才进行转移,保证元素顺序if (outbox.empty()) {while (!inbox.empty()) {outbox.push(inbox.top());inbox.pop();}}}public:// 入队操作void enqueue(int val) {inbox.push(val);}// 出队操作int dequeue() {if (empty()) {throw runtime_error("Queue underflow");}transfer();  // 确保outbox不为空int val = outbox.top();outbox.pop();return val;}// 获取队头元素int front() {if (empty()) {throw runtime_error("Queue is empty");}transfer();  // 确保outbox不为空return outbox.top();}// 检查队列是否为空bool empty() const {return inbox.empty() && outbox.empty();}// 返回队列中的元素数量int size() const {return inbox.size() + outbox.size();}
};// 使用两个队列实现栈
class QueueStack {
private:queue<int> q1;  // 主队列,存储所有元素queue<int> q2;  // 辅助队列,用于操作public:// 入栈操作void push(int val) {// 将新元素加入主队列q1.push(val);}// 出栈操作int pop() {if (empty()) {throw runtime_error("Stack underflow");}// 将q1中除最后一个元素外的所有元素移到q2while (q1.size() > 1) {q2.push(q1.front());q1.pop();}// 保存最后一个元素(栈顶元素)int val = q1.front();q1.pop();// 交换q1和q2的角色swap(q1, q2);return val;}// 获取栈顶元素int top() {if (empty()) {throw runtime_error("Stack is empty");}// 将q1中除最后一个元素外的所有元素移到q2while (q1.size() > 1) {q2.push(q1.front());q1.pop();}// 保存最后一个元素(栈顶元素)int val = q1.front();// 将最后一个元素也移到q2q2.push(val);q1.pop();// 交换q1和q2的角色swap(q1, q2);return val;}// 检查栈是否为空bool empty() const {return q1.empty();}// 返回栈中的元素数量int size() const {return q1.size();}
};// 测试程序
int main() {cout << "===== Testing Queue implemented with Stacks =====" << endl;StackQueue queue;cout << "Enqueuing: 10, 20, 30" << endl;queue.enqueue(10);queue.enqueue(20);queue.enqueue(30);cout << "Queue size: " << queue.size() << endl;cout << "Front element: " << queue.front() << endl;cout << "Dequeuing: " << queue.dequeue() << endl;cout << "Front element after dequeue: " << queue.front() << endl;cout << "Queue size after dequeue: " << queue.size() << endl;cout << "Enqueuing: 40" << endl;queue.enqueue(40);cout << "Queue size: " << queue.size() << endl;cout << "Emptying queue..." << endl;while (!queue.empty()) {cout << "Dequeued: " << queue.dequeue() << endl;}cout << "\n===== Testing Stack implemented with Queues =====" << endl;QueueStack stack;cout << "Pushing: 10, 20, 30" << endl;stack.push(10);stack.push(20);stack.push(30);cout << "Stack size: " << stack.size() << endl;cout << "Top element: " << stack.top() << endl;cout << "Popping: " << stack.pop() << endl;cout << "Top element after pop: " << stack.top() << endl;cout << "Stack size after pop: " << stack.size() << endl;cout << "Pushing: 40" << endl;stack.push(40);cout << "Stack size: " << stack.size() << endl;cout << "Top element: " << stack.top() << endl;cout << "Emptying stack..." << endl;while (!stack.empty()) {cout << "Popped: " << stack.pop() << endl;}return 0;
}

1.3.9

编写一段程序,从标准输入得到一个缺少左括号的表达式并打印出补全括号之后的中序表达式。例如,给定输入:[需要图示]你的程序应该输出:[需要图示]

#include <iostream>
#include <stack>
#include <string>
using namespace std;string fixExpression(string& expr) {stack<string> operands;for (char c : expr) {if (c == ')') {// 遇到右括号,需要添加对应的左括号if (!operands.empty()) {string top = operands.top();operands.pop();top = "(" + top + ")";if (!operands.empty()) {// 将补全的表达式与前面的部分合并string prev = operands.top();operands.pop();operands.push(prev + top);} else {operands.push(top);}}} else if (c == '+' || c == '-' || c == '*' || c == '/') {// 遇到操作符,将其添加到前一个操作数之后if (!operands.empty()) {string top = operands.top();operands.pop();top = top + c;operands.push(top);}} else {// 处理操作数(数字或变量)string operand(1, c);if (!operands.empty()) {string prev = operands.top();operands.pop();operands.push(prev + operand);} else {operands.push(operand);}}}return operands.empty() ? "" : operands.top();
}int main() {string expression;cin >> expression;cout << fixExpression(expression) << endl;return 0;
}

1.3.10

编写一个过滤器InfixToPostfix,将算术表达式由中序表达式转为后序表达式。

#include <iostream>
#include <string>
#include <stack>
#include <cctype>using namespace std;class InfixToPostfix {
public:// 获取操作符的优先级int getPrecedence(char op) {if (op == '+' || op == '-')return 1;if (op == '*' || op == '/')return 2;return 0;  // 括号的优先级最低}// 中序表达式转后序表达式的主函数string convert(const string& infix) {string postfix = "";stack<char> operatorStack;for (int i = 0; i < infix.length(); i++) {char c = infix[i];// 如果是空格,跳过if (c == ' ')continue;// 如果是操作数(数字或字母),直接添加到结果中if (isalnum(c)) {postfix += c;}// 如果是左括号,入栈else if (c == '(') {operatorStack.push(c);}// 如果是右括号,弹出栈中元素直到遇到左括号else if (c == ')') {while (!operatorStack.empty() && operatorStack.top() != '(') {postfix += operatorStack.top();operatorStack.pop();}// 弹出左括号if (!operatorStack.empty() && operatorStack.top() == '(') {operatorStack.pop();}}// 如果是运算符else {// 弹出优先级大于或等于当前运算符的所有运算符while (!operatorStack.empty() && operatorStack.top() != '(' && getPrecedence(operatorStack.top()) >= getPrecedence(c)) {postfix += operatorStack.top();operatorStack.pop();}// 当前运算符入栈operatorStack.push(c);}}// 处理栈中剩余的运算符while (!operatorStack.empty()) {if (operatorStack.top() != '(') {postfix += operatorStack.top();}operatorStack.pop();}return postfix;}
};int main() {InfixToPostfix converter;string infix;cout << "请输入中序表达式: ";getline(cin, infix);string postfix = converter.convert(infix);cout << "后序表达式: " << postfix << endl;return 0;
}

1.3.11

编写一段程序EvaluatePostfix,从标准输入中得到一个后序表达式,求值并打印结果(将上一题的程序中得到的输出用管道传递给这一段程序可以得到和Evaluate相同的行为)。

const int maxn = 1e4 + 50;
int st[maxn],idx;
class Solution {
public:int evalRPN(vector<string>& tokens) {idx = -1;for(const auto& t : tokens){if(t != "+" and t != "-" and t != "*" and t != "/"){st[++idx] = stoi(t);}else{auto a = st[idx--];auto b = st[idx--];if(t == "+") st[++idx] = b + a;else if(t == "-") st[++idx] = b - a;else if(t == "*") st[++idx] = b * a;else st[++idx] = b / a;}}return st[idx];}
};

1.3.12

编写一个可迭代的Stack用例,它含有一个静态的copy()方法,接受一个字符串的栈作为参数并返回该栈的一个副本。注意:这种能力是迭代器价值的一个重要体现,因为有了它我们无需改变基本API就能够实现这种功能。

1.3.14

编写一个类ResizingArrayQueueOfStrings,使用定长数组实现队列的抽象,然后扩展实现,使用调整数组的方法突破大小的限制。

1.3.15

编写一个Queue的用例,接受一个命令行参数k并打印出标准输入中的倒数第k个字符串(假设标准输入中至少有k个字符串)。

#include <iostream>
#include <string>
#include <deque>
#include <stdexcept>int main(int argc, char* argv[]) {// 检查命令行参数if (argc != 2) {std::cerr << "用法: " << argv[0] << " k" << std::endl;return 1;}// 解析参数kint k;try {k = std::stoi(argv[1]);if (k <= 0) {throw std::invalid_argument("k必须是正整数");}} catch (const std::exception& e) {std::cerr << "错误: " << e.what() << std::endl;return 1;}// 使用deque作为循环缓冲区std::deque<std::string> buffer;std::string line;// 从标准输入读取字符串while (std::getline(std::cin, line)) {if (!line.empty()) {// 将字符串加入缓冲区buffer.push_back(line);// 如果缓冲区大小超过k,移除最早的元素if (buffer.size() > k) {buffer.pop_front();}}}// 检查输入是否至少有k个字符串if (buffer.size() < k) {std::cerr << "错误:输入中的字符串数量少于" << k << "个" << std::endl;return 1;}// 打印倒数第k个字符串// 在含有k个元素的缓冲区中,最前面的元素就是倒数第k个std::cout << buffer.front() << std::endl;return 0;
}

链表练习

struct Node{String item;int val;Node* next;Node(string s, Node* nxt = nullptr) : item(s), val(0), next(nxt) {} Node(int v, Node* nxt = nullptr) : item(""), val(v), next(nxt) {}
};

1.3.19

给出一段代码,删除链表的尾结点,其中链表的首结点为first。

void removeTail(Node* first){Node* cur = first;if(first == nullptr || first->next ==nullptr){delete first;first = nullptr;return;}while(cur->next->next!=nullptr){cur = cur->next;}delete cur->next;cur->next = nullptr;
}

1.3.20

编写一个方法delete(),接受一个int参数k,删除链表的第k个元素(如果它存在的话)。


void delete(int k,Node* first){if(first ==nullptr) return;if(k==1){Node *tmp = first;first = first->next;delete tmp;return;}// 寻找第k-1个结点Node* cur = first;int i = 1;while(i<k-1&&cur!=nullptr){cur = cur->next;i++;}// 如果找不到第k个节点说明链表比k短if(cur==nullptr||cur->next == nullptr) return;Node* tmp = cur->next;cur->next = tmp->next;delete tmp;
}

1.3.21

编写一个方法find(),接受一条链表和一个字符串key作为参数。如果链表中的某个结点的item域的值为key,则方法返回true,否则返回false。

bool find(Node* first, const string& key) {Node* cur = first;while (cur != nullptr) {if (cur->item == key) {return true;}cur = cur->next;}return false;
}

1.3.24

编写一个方法 removeAfter(),接受一个链表结点作为参数并删除该结点的后续结点(如果参数结点或参数结点的后续结点为空则什么也不做)。

void removeAfter(Node* node) {// 如果结点为空或结点的后续结点为空,什么也不做if (node == nullptr || node->next == nullptr) return;// 保存后续结点的引用Node* toDelete = node->next;// 更新链接,跳过后续结点node->next = toDelete->next;// 删除后续结点delete toDelete;
}

1.3.25

编写一个方法 insertAfter(),接受两个链表结点作为参数,将第二个结点插入链表并使之成为第一个结点的后续结点(如果两个参数为空则什么也不做)。

void insertAfter(Node* first, Node* second) {// 如果任一结点为空,什么也不做if (first == nullptr || second == nullptr) return;// 将second插入到first之后second->next = first->next;first->next = second;
}

1.3.26

编写一个方法 remove(),接受一条链表和一个字符串 key 作为参数,删除链表中所有 item 域为 key 的结点。

void remove(Node* head,const string& key){if(head!=nullptr&&head->item==key){{Node* toDelete = head;head = toDelete->next;delete toDelete;}if(head==nullptr) return;Node* cur = head;while(cur->next!=nullptr){if(cur->next->item==key){Node* tmp = cur->next;cur->next = tmp->next;delete tmp;// cur = cur->next;  }else {cur = cur->next;}}
}
void remove(Node* &head, const string& key) {// 处理头部节点while (head != nullptr && head->item == key) {Node* toDelete = head;head = head->next;delete toDelete;}// 如果链表变为空if (head == nullptr) return;// 处理剩余节点Node* cur = head;while (cur->next != nullptr) {if (cur->next->item == key) {Node* toDelete = cur->next;cur->next = toDelete->next;delete toDelete;// 注意这里不移动cur,因为cur->next已经变成了新的节点} else {cur = cur->next;}}
}

1.3.27

编写一个方法 max(),接受一条链表的首结点作为参数,返回链表中最大的节点的值。假设所有链接均为正整数,如果链表为空则返回0。

// 1.3.27 返回链表中最大的节点值(假设为整数)
int max(Node* first) {// 如果链表为空,返回0if (first == nullptr) return 0;int maxVal = first->val;Node* cur = first->next;while (cur != nullptr) {if (cur->val > maxVal) {maxVal = cur->val;}cur = cur->next;}return maxVal;
}

1.3.28

用递归解答上一题。

int max(Node* first) {// 基本情况:如果链表为空,返回0if (first == nullptr) return 0;// 递归计算剩余链表中的最大值int restMax = max(first->next);// 返回当前节点值和剩余最大值中的较大者return (first->val > restMax) ? first->val : restMax;
}

1.3.29

用环形链表实现 Queue。环形链表也是一条链表,只是没有任何结点的链接为空,且只需链接非空则 last.next 的值为 first。只能使用一个 Node 类型的实例变量(last)。

struct Node{string item; // 节点存储的数据 Node* next; // 指向下一个节点的指针 // 构造函数 Node(const string& data) : item(data), next(nullptr) {}
}class MyQueue{Node* last;int n;
public:CircularQueue() : last(nullptr), n(0) {}// 检查队列是否为空bool isEmpty() const {return last == nullptr;}// 返回队列中的元素数量int size() const {return n;}// 入队操作(在队尾添加元素)void enqueue(const string& item) {Node* newNode = new Node(item);if (isEmpty()) {// 如果队列为空,创建一个只有一个节点的环newNode->next = newNode;last = newNode;} else {// 将新节点插入到环中,成为新的last->next之后的节点newNode->next = last->next;last->next = newNode;// 更新last指向新节点last = newNode;}n++;}// 出队操作(从队头移除元素)string dequeue() {if (isEmpty()) {throw runtime_error("Queue underflow");}// 获取队头元素(last->next)Node* first = last->next;string item = first->item;if (first == last) {// 如果队列中只有一个元素delete first;last = nullptr;} else {// 从环中移除队头元素last->next = first->next;delete first;}n--;return item;}// 获取队头元素(不移除)string peek() const {if (isEmpty()) {throw runtime_error("Queue underflow");}return last->next->item;}
}

1.3.31

在两个有序链表中的三个变量的作用:reverse、first 和 second。在递归实现中,我们从原链表中提取结点 first 并将它插入到逆链表的开头。我们需要一直保持 first 指向原链表中所有剩余结点的首结点,second 指向原链表中所有剩余结点的第二个结点。

提取的题目还包括两个关于链表反转的实现:

  1. 使用迭代方法实现链表反转函数 reverse()
  2. 使用递归方法实现链表反转函数 reverse()
#include <iostream>
using namespace std;// 单向链表节点结构
class Node {
public:int data;Node* next;// 构造函数Node(int val) : data(val), next(nullptr) {}
};// 打印链表(用于测试)
void printList(Node* head) {Node* current = head;while (current != nullptr) {cout << current->data << " -> ";current = current->next;}cout << "nullptr" << endl;
}// 创建测试链表
Node* createTestList() {Node* head = new Node(1);head->next = new Node(2);head->next->next = new Node(3);head->next->next->next = new Node(4);head->next->next->next->next = new Node(5);return head;
}// 释放链表内存
void freeList(Node* head) {while (head != nullptr) {Node* temp = head;head = head->next;delete temp;}
}// 使用迭代方法实现链表反转
Node* reverseIterative(Node* head) {Node* reverse = nullptr;  // 反转后的链表头Node* first = head;       // 指向原链表中所有剩余结点的首结点while (first != nullptr) {Node* second = first->next;  // 指向原链表中所有剩余结点的第二个结点// 将 first 插入到反转链表的开头first->next = reverse;reverse = first;// 移动到下一个节点first = second;}return reverse;
}// 使用递归方法实现链表反转
Node* reverseRecursive(Node* head) {// 基本情况:空链表或只有一个节点if (head == nullptr || head->next == nullptr) {return head;}// first 指向原链表的第一个节点Node* first = head;// second 指向原链表的第二个节点Node* second = first->next;// 递归反转剩余的链表(从第二个节点开始)Node* rest = reverseRecursive(second);// 将第一个节点连接到反转后链表的末尾second->next = first;first->next = nullptr;return rest;
}// 另一种递归实现(更接近题目描述)
Node* reverseRecursiveAlt(Node* first) {// 基本情况:空链表if (first == nullptr) return nullptr;// 基本情况:只有一个节点if (first->next == nullptr) return first;// second 指向原链表的第二个节点Node* second = first->next;// 递归反转剩余的链表(从第二个节点开始)Node* rest = reverseRecursiveAlt(second);// 将第二个节点指向第一个节点second->next = first;// 将第一个节点指向 nullptr(它将成为新链表的最后一个节点)first->next = nullptr;return rest;
}int main() {// 测试迭代方法return 0;
}

1.3.32

实现一个泛型类 DoubleNode 用来构造双向链表,其中每个结点都含有一个指向前面元素的引用和一项指向后面元素的引用(如果不存在则为 null)。为以下任务实现若干静态方法:在表头插入结点、在表尾插入结点、从表头删除结点、从表尾删除结点、在指定结点之前插入新结点、在指定结点之后插入新结点、删除指定结点。

#include <iostream>
#include <stdexcept>
using namespace std;// 泛型双向链表节点类
template <typename T>
class DoubleNode {
public:T data;DoubleNode<T>* prev;DoubleNode<T>* next;// 构造函数DoubleNode(T val) : data(val), prev(nullptr), next(nullptr) {}
};// 双向链表操作的静态方法类
template <typename T>
class DoublyLinkedList {
public:// 在表头插入结点static DoubleNode<T>* insertAtHead(DoubleNode<T>* head, T val) {DoubleNode<T>* newNode = new DoubleNode<T>(val);if (head == nullptr) {return newNode;}newNode->next = head;head->prev = newNode;return newNode;}// 在表尾插入结点static DoubleNode<T>* insertAtTail(DoubleNode<T>* head, T val) {DoubleNode<T>* newNode = new DoubleNode<T>(val);if (head == nullptr) {return newNode;}// 找到链表的尾结点DoubleNode<T>* current = head;while (current->next != nullptr) {current = current->next;}current->next = newNode;newNode->prev = current;return head;}// 从表头删除结点static DoubleNode<T>* removeFromHead(DoubleNode<T>* head) {if (head == nullptr) {throw runtime_error("Cannot remove from empty list");}DoubleNode<T>* newHead = head->next;if (newHead != nullptr) {newHead->prev = nullptr;}delete head;return newHead;}// 从表尾删除结点static DoubleNode<T>* removeFromTail(DoubleNode<T>* head) {if (head == nullptr) {throw runtime_error("Cannot remove from empty list");}// 如果只有一个节点if (head->next == nullptr) {delete head;return nullptr;}// 找到尾结点和倒数第二个结点DoubleNode<T>* current = head;while (current->next != nullptr) {current = current->next;}// 删除尾结点DoubleNode<T>* newTail = current->prev;newTail->next = nullptr;delete current;return head;}// 在指定结点之前插入新结点static DoubleNode<T>* insertBefore(DoubleNode<T>* head, DoubleNode<T>* node, T val) {if (head == nullptr || node == nullptr) {throw runtime_error("Invalid operation");}// 如果在头结点之前插入if (node == head) {return insertAtHead(head, val);}DoubleNode<T>* newNode = new DoubleNode<T>(val);DoubleNode<T>* prevNode = node->prev;newNode->next = node;newNode->prev = prevNode;node->prev = newNode;prevNode->next = newNode;return head;}// 在指定结点之后插入新结点static DoubleNode<T>* insertAfter(DoubleNode<T>* head, DoubleNode<T>* node, T val) {if (head == nullptr || node == nullptr) {throw runtime_error("Invalid operation");}DoubleNode<T>* newNode = new DoubleNode<T>(val);DoubleNode<T>* nextNode = node->next;newNode->prev = node;newNode->next = nextNode;node->next = newNode;if (nextNode != nullptr) {nextNode->prev = newNode;}return head;}// 删除指定结点static DoubleNode<T>* remove(DoubleNode<T>* head, DoubleNode<T>* node) {if (head == nullptr || node == nullptr) {throw runtime_error("Invalid operation");}// 如果删除的是头结点if (node == head) {return removeFromHead(head);}DoubleNode<T>* prevNode = node->prev;DoubleNode<T>* nextNode = node->next;prevNode->next = nextNode;if (nextNode != nullptr) {nextNode->prev = prevNode;}delete node;return head;}// 查找指定值的节点static DoubleNode<T>* find(DoubleNode<T>* head, T val) {DoubleNode<T>* current = head;while (current != nullptr) {if (current->data == val) {return current;}current = current->next;}return nullptr;}// 打印链表(用于测试)static void printList(DoubleNode<T>* head) {cout << "Forward: nullptr <-> ";DoubleNode<T>* current = head;while (current != nullptr) {cout << current->data << " <-> ";current = current->next;}cout << "nullptr" << endl;// 从尾到头打印链表(验证prev指针)cout << "Backward: nullptr <-> ";if (head != nullptr) {// 找到尾结点current = head;while (current->next != nullptr) {current = current->next;}// 从尾到头打印while (current != nullptr) {cout << current->data << " <-> ";current = current->prev;}}cout << "nullptr" << endl;}// 释放链表内存static void freeList(DoubleNode<T>* head) {while (head != nullptr) {DoubleNode<T>* temp = head;head = head->next;delete temp;}}
};// 测试程序
int main() {DoubleNode<int>* list = nullptr;return 0;
}

lc

138 随机链表的复制

25 k个一组反转链表

实现最小栈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/81407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GD32F407单片机开发入门(十七)内部RTC实时时钟及实战含源码

文章目录 一.概要二.RTC基本特点三.GD32单片机RTC内部结构图四.配置一个RTC走秒例程五.工程源代码下载六.小结 一.概要 RTC&#xff08;Real-Time Clock&#xff09;是一种用于追踪和记录实际时间的时钟系统。RTC模块提供了一个包含日期&#xff08;年/月/日&#xff09;和时间…

新能源汽车运动控制器核心芯片选型与优化:MCU、DCDC与CANFD协同设计

摘要&#xff1a;随着新能源汽车产业的迅猛发展&#xff0c;汽车运动控制器的性能和可靠性面临着更高的要求。本文深入探讨了新能源汽车运动控制器中MCU&#xff08;微控制单元&#xff09;、DCDC电源管理芯片和CANFD总线通信芯片的选型要点、优化策略及其协同设计方案。通过综…

2.maven 手动安装 jar包

1.背景 有的时候&#xff0c;maven仓库无法下载&#xff0c;可以手动安装。本文以pentaho-aggdesigner-algorithm-5.1.5-jhyde.jar为例。 2.预先准备 下载文件到本地指定位置。 2.1.安装pom mvn install:install-file \-Dfile/home/wind/tmp/pentaho-aggdesigner-5.1.5-jh…

OpenCV 图形API(75)图像与通道拼接函数-----将 4 个单通道图像矩阵 (GMat) 合并为一个 4 通道的多通道图像矩阵函数merge4()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 由4个单通道矩阵创建一个4通道矩阵。 该函数将多个矩阵合并为一个单一的多通道矩阵。也就是说&#xff0c;输出矩阵的每一个元素都是输入矩阵对…

AI日报 · 2025年05月02日 | 再见GPT-4!OpenAI CEO 确认 GPT-4 已从 ChatGPT 界面正式移除

1、OpenAI CEO 确认 GPT-4 已从 ChatGPT 界面正式移除 在处理 GPT-4o 更新问题的同时&#xff0c;OpenAI CEO Sam Altman 于 5 月 1 日在 X 平台发文&#xff0c;正式确认初代 GPT-4 模型已从 ChatGPT 主用户界面中移除。此举遵循了 OpenAI 此前公布的计划&#xff0c;即在 4 …

patch命令在代码管理中的应用

patch 是一个用于将差异文件&#xff08;补丁&#xff09;应用到源代码的工具&#xff0c;常用于修复 bug、添加功能或调整代码结构。在您提供的代码中&#xff0c;patch 命令通过一系列补丁文件&#xff08;.patch&#xff09;修改了 open-amp 库的源代码。 patch 命令的核心作…

spring-ai集成langfuse

1、pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

PyTorch 与 TensorFlow:深度学习框架的深度剖析与实战对比

PyTorch 与 TensorFlow&#xff1a;深度学习框架的深度剖析与实战对比 摘要 &#xff1a;本文深入对比 PyTorch 与 TensorFlow 两大深度学习框架&#xff0c;从核心架构、优缺点、适用场景等多维度剖析&#xff0c;结合实例讲解&#xff0c;帮助开发者清晰理解两者特性&#x…

如何配置NGINX作为反向代理服务器来缓存后端服务的响应?

大家好&#xff0c;我是锋哥。今天分享关于【如何配置NGINX作为反向代理服务器来缓存后端服务的响应&#xff1f;】面试题。希望对大家有帮助&#xff1b; 如何配置NGINX作为反向代理服务器来缓存后端服务的响应&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源…

DiT:文档图像Transformer 的自监督预训练

摘要 图像transformer&#xff08;Image Transformer&#xff09;最近在自然图像理解方面取得了显著进展&#xff0c; 无论是使用监督&#xff08;ViT、DeiT等&#xff09;还是自监督&#xff08;BEiT、MAE等&#xff09;预训练技术。在本文中&#xff0c;我们提出了DiT&#…

51c嵌入式~电路~合集4

我自己的原文哦~ https://blog.51cto.com/whaosoft/11888986 一、电流检测电路 电流检测的应用 电路检测电路常用于&#xff1a;高压短路保护、电机控制、DC/DC换流器、系统功耗管理、二次电池的电流管理、蓄电池管理等电流检测等场景。电路专辑 对于大部分应用&#xff…

【Git】万字详解 Git 的原理与使用(上)

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 初识 Git1.1 Git 是什么&#xff1f;1.2 为什么要有 Git 2. 安装 Git2.1 Linux-Ubuntu 安装 Git2.2 Windo…

【原创开发】无印去水印[特殊字符]短视频去水印工具[特殊字符]支持一键批量解析

支持&#xff1a;快手&#xff0c;抖音&#xff0c;小红书&#xff0c;哔哩哔哩&#xff0c;等多款应用去水印&#xff0c;支持图集解析下载 【应用名称】&#xff1a;无印 【应用版本】&#xff1a;1.3 【应用大小】&#xff1a;17M 【测试机型】&#xff1a;小米14 【下载链…

qemu(3) -- qemu-arm使用

1. 前言 qemu中有很多的特技&#xff0c;此处记录下qemu-arm的使用方式&#xff0c;简单来说qemu-system-xx用于虚拟整个设备&#xff0c;包括操作系统的运行环境&#xff0c;而qemu-xx仅虚拟Linux应用程序的环境&#xff0c;不涉及操作系统&#xff0c;应用程序的系统调用有宿…

Docker的简单使用(不全)

Docker Hello World Docker 允许在容器内运行应用程序&#xff0c;使用docker run命令来在容器内运行一个应用程序 输出Hello World runoobrunoob:~$ docker run ubuntu:15.10 /bin/echo "Hello world"Hello world docker&#xff1a;Docker的二进制执行文件 run…

SALOME源码分析: 命令系统

本文分析SALOME中命令系统&#xff0c;涉及的知识点包括&#xff0c; MDF框架数据对象模型 注1&#xff1a;限于研究水平&#xff0c;分析难免不当&#xff0c;欢迎批评指正。注2&#xff1a;文章内容会不定期更新。 一、命令对象 1.1 Class Hierarchy 1.2 SUIT_Operation #…

Bootstrap(自助法)​​:无需假设分布的统计推断工具

核心思想​​ Bootstrap 是一种​​重采样&#xff08;Resampling&#xff09;技术​​&#xff0c;通过在原始数据中​​有放回地重复抽样​​&#xff0c;生成大量新样本集&#xff0c;用于估计统计量&#xff08;如均值、方差&#xff09;的分布或模型性能的不确定性。 ​​…

沙箱逃逸(Python沙盒逃逸深度解析)

沙箱逃逸&#xff08;Python沙盒逃逸深度解析&#xff09; 一、沙盒逃逸的核心目标 执行系统命令 通过调用os.system、subprocess.Popen等函数执行Shell命令&#xff0c;例如读取文件或反弹Shell。 文件操作 读取敏感文件&#xff08;如/etc/passwd&#xff09;、写入后门文件…

融智学数学符号体系的系统解读(之一)

融智学数学符号体系的系统解读 一、道函数&#xff08;Dao Function&#xff09; 数学表达式&#xff1a; f(x,y,z)0&#xff08;狭义&#xff09; f(x,y,z,ict)0&#xff08;广义&#xff09; 符号解析&#xff1a; x: 形象思维坐标轴 数学意义: 表征基于感官输入的多模…

Java 中使用正则表达式

1. 引入包 在使用正则表达式之前,需要引入包: import java.util.regex.Matcher; import java.util.regex.Pattern; 2. 常用模式规则 元字符 :这些是正则表达式中的特殊字符,用于匹配特定的模式。 . :匹配任意单个字符(换行符除外)。例如,a.b 可以匹配 "acb&quo…