707.設計連結串列
阿新 • • 發佈:2021-11-03
題目連結:
題目描述
設計連結串列的實現。您可以選擇使用單鏈表或雙鏈表。單鏈表中的節點應該具有兩個屬性:val 和 next。val 是當前節點的值,next 是指向下一個節點的指標/引用。如果要使用雙向連結串列,則還需要一個屬性 prev 以指示連結串列中的上一個節點。假設連結串列中的所有節點都是 0-index 的。
在連結串列類中實現這些功能:
-
get(index):獲取連結串列中第 index 個節點的值。如果索引無效,則返回-1。
-
addAtHead(val):在連結串列的第一個元素之前新增一個值為 val 的節點。插入後,新節點將成為連結串列的第一個節點。
-
addAtTail(val):將值為 val 的節點追加到連結串列的最後一個元素。
-
addAtIndex(index,val):在連結串列中的第 index 個節點之前新增值為 val 的節點。如果 index 等於連結串列的長度,則該節點將附加到連結串列的末尾。如果 index 大於連結串列長度,則不會插入節點。如果index小於0,則在頭部插入節點。
-
deleteAtIndex(index):如果索引 index 有效,則刪除連結串列中的第 index 個節點。
示例:
MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //連結串列變為1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //現在連結串列是1-> 3
linkedList.get(1); //返回3
提示:
所有val值都在 [1, 1000] 之內。
操作次數將在 [1, 1000] 之內。
請不要使用內建的 LinkedList 庫。
思路:這道題需要掌握連結串列的基本操作。新增”虛擬頭節點“能讓首元節點的操作同非首元節點的操作一致。
程式碼(C++版本):
1、單鏈表
#include "iostream" using namespace std; //單鏈表 class MyLinkedList { public: struct LinkedNode { int val; LinkedNode *next; LinkedNode(intval) : val(val), next(NULL) {} }; private: LinkedNode* headNode; int size; public: //初始化連結串列 //如果連結串列帶有一個虛擬頭節點,那麼首元節點的操作也跟其他節點的操作一致,否則要單獨考慮對首元節點的操作 MyLinkedList() { headNode = new LinkedNode(0);//頭節點為虛擬節點 size = 0; } //獲取連結串列中第 index 個節點的值。如果索引無效,則返回-1。 //不包括頭節點,首元節點的索引為0 int get(int index) { if (index < 0 || index > size - 1) { return -1; } int i = 0;//用於計數 LinkedNode* tp = headNode; while (tp->next != NULL) { if (i == index) { return tp->next->val; } else { i++; tp = tp->next; } } return -1; } //在連結串列的第一個元素之前新增一個值為 val 的節點。插入後,新節點將成為連結串列的第一個節點。 //頭節點除外,第一個元素是首元節點 void addAtHead(int val) { LinkedNode* node = new LinkedNode(val); node->next = headNode->next; headNode->next = node; size += 1; } // 錯誤寫法,這樣會改變頭指標所指的內容(在類中定義的函式,相對於對頭節點加了&) // //將值為 val 的節點追加到連結串列的最後一個元素。 // void addAtTail(int val) { // LinkedNode* node = new LinkedNode(val); // while (headNode->next != NULL) { // headNode = headNode->next; // } // headNode->next = node; // size += 1; // } //將值為 val 的節點追加到連結串列的最後一個元素。 void addAtTail(int val) { LinkedNode* node = new LinkedNode(val); LinkedNode* tp = headNode; while (tp->next != NULL) { tp = tp->next; } tp->next = node; size += 1; } // 在連結串列中的第index個節點之前新增值為val的節點。 // 如果index等於連結串列的長度,則該節點將附加到連結串列的末尾。 // 如果 index 大於連結串列長度,則不會插入節點。 // 如果index小於0,則在頭部插入節點。 void addAtIndex(int index, int val) { if (index == size ) { addAtTail(val); } else if (index > size) { return; } else if (index < 0) { addAtHead(val); } else { LinkedNode* node = new LinkedNode(val); LinkedNode* tp = headNode; for (int i = 0; i < index; i++) { tp = tp->next; } node->next = tp->next; tp->next = node; size += 1; } } //deleteAtIndex(index):如果索引 index 有效,則刪除連結串列中的第 index 個節點。 void deleteAtIndex(int index) { if (index >= 0 && index < size) { LinkedNode* tp = headNode; for (int i = 0; i < index; i++) { tp = tp->next; } LinkedNode* dp = tp->next; tp->next = tp->next->next; delete dp; size -= 1; } } //列印連結串列 void printLinkedList() { LinkedNode* tp = headNode; while (tp->next != NULL) { cout << tp->next->val << " "; tp = tp->next; } cout << endl; } }; int main() { MyLinkedList* linkedList = new MyLinkedList(); linkedList->addAtHead(1); linkedList->printLinkedList(); linkedList->addAtTail(3); linkedList->printLinkedList(); linkedList->addAtIndex(1, 2); //連結串列變為1-> 2-> 3 linkedList->printLinkedList(); int r1 = linkedList->get(1); //返回2 cout << r1 << endl; linkedList->deleteAtIndex(1); //現在連結串列是1-> 3 linkedList->printLinkedList(); int r2 = linkedList->get(1); //返回3 cout << r2 << endl; return 0; }
分析
-
時間複雜度: addAtHead: O(1) addAtInder,get,deleteAtIndex: O(k),其中 k 指的是元素的索引。 addAtTail:O(N),其中 N 指的是連結串列的元素個數。
-