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

算法四 习题 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.xdnf.cn/news/3196.html

相关文章:

  • Vue 项目中运行 `npm run dev` 时发生的过程
  • 代码随想录算法训练营Day39
  • 数据科学与计算
  • Ecology中拦截jquery.ajax请求接口后的数据
  • 【Linux更新openSSH服务】
  • GNU gettext 快速上手
  • 论文公式根据章节自动编号教程
  • DeepSeek-Prover-V2-671B 简介、下载、体验、微调、数据集:专为数学定理自动证明设计的超大垂直领域语言模型(在线体验地址)
  • 涨薪技术|0到1学会性能测试第42课-apache监控与调优
  • 应对过度处方挑战:为药物推荐任务微调大语言模型(Xiangnan He)
  • K8S - HPA + 探针实战 - 实现弹性扩缩与自愈
  • 详解 MyBatis-Plus 框架中 QueryWrapper 类
  • Compose笔记(二十一)--AnimationVisibility
  • 学习笔记——《Java面向对象程序设计》-常用实用类
  • Python爬虫(11)Python数据存储实战:深入解析NoSQL数据库的核心应用与实战
  • OpenCV实战教程:从零开始的计算机视觉之旅
  • 鸿蒙NEXT开发动画(方块动画旋转)
  • ESP32开发-作为TCP服务端接收数据
  • 配置和使用基本存储
  • 大型连锁酒店集团数据湖应用示例
  • 关于vue+iview中tabs嵌套及实际应用
  • 如何在uni-app中自定义输入框placeholder的样式
  • 2025年“深圳杯”数学建模挑战赛D题-法医物证多人身份鉴定问题
  • TCP和UDP的数据传输+区别
  • JavaScript的3D库有哪些?
  • 第六章 QT基础:9、Qt中数据库的操作
  • 自主采集高质量三维重建数据集指南:面向3DGS与NeRF的图像与视频拍摄技巧【2025最新版!!】
  • 『深夜_MySQL』详解数据库 探索数据库是如何存储的
  • 泰迪杯特等奖案例学习资料:基于多模态融合与边缘计算的智能温室环境调控系统
  • 负载均衡技术全景指南:架构、算法与发展趋势