算法四 習題 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.pswp.cn/diannao/81407.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81407.shtml
英文地址,請注明出處:http://en.pswp.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…