链表( Linked List )
链表是一种线性数据结构,由一系列节点组成。每个节点包含两个部分,一个是存储数据的部分,另一个是指向下一个节点的指针。与数组不同的是,链表中的节点在内存中不一定是连续存储的。
链表可以分为单向链表和双向链表两种类型。在单向链表中,每个节点只有一个指向下一个节点的指针,而在双向链表中,每个节点有两个指针,一个指向前一个节点,另一个指向后一个节点。
链表的插入和删除操作非常高效,因为只需要修改节点的指针即可完成操作。但是,链表的访问操作需要从头节点开始,逐个遍历直到找到目标节点,时间复杂度为O(n),相比数组的O(1)访问时间要慢很多。
链表的优点是可以灵活地动态添加和删除节点,而且在内存管理方面比数组更加灵活。链表广泛应用于算法和数据结构中,例如链表可以用来实现栈、队列、哈希表等数据结构。
因为单链表比较简单,结构也比较单一,本篇文章就不做介绍
双链表 ( Doubly Linked List )
双链表 (DLL) 包含一个额外的指针 prev
,以及 next
指针和链表中的 data
声明
我们以c++中的类为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Node { public: int data; Node* next; Node* prev; Node(int val) { data = val; prev = NULL; next = NULL; } };
|
这段代码定义了一个名为 Node
的类,它表示双链表中的一个节点。该类具有三个成员变量:
int data
:该节点存储的数据。
Node* next
:指向双链表中的下一个节点,它是一个指针类型。
Node* prev
:指向双链表中的前一个节点,它也是一个指针类型。
在双链表中,每个节点都有两个指针,一个指向前一个节点,一个指向后一个节点。因此,通过定义prev
和next
两个指针变量,该类实现了双链表节点的功能。
插入节点
可以通过四种方式添加节点:
- 在 DLL 的前面
- 在给定节点之后
- 在 DLL 的末尾
- 在给定节点之前
为了使用起来更方便,再声明一个名为 Doubly linked list
的类
1 2 3 4 5 6 7
| class DoublyLinkedList { public: Node* head; DoublyLinkedList() { head = NULL; } }
|
现在我们为它添加方法
在DLL头部插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| void insertAtHead(int val) { Node* newNode = new Node(val);
newNode->data = val;
if (head == NULL) { head = newNode; }
newNode->next = head;
head->prev = newNode;
head = newNode; }
|
在给定位置之后插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void insertAfter(int pos, int val) { Node* current = head; int count = 1; while (count < pos - 1 && current != NULL) { current = current->next; count++; } if (current == NULL) cout << "Invalid position" << endl; else { newNode->next = current->next; newNode->prev = current; if (current->next != NULL) current->next->prev = newNode; current->next = newNode; } }
|
如果你不知道之前节点的 prev
指针,那么就需要像上面这样从头开始遍历(或从尾 这里不细写了,思想是一样的)
如果要从知道的某一节点之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void insertAfter(Node* prevNode, int val) { if (prev_node == NULL) { cout << "the given previous node cannot be NULL"; return; } Node* newNode = new Node(val); newNode->next = prevNode->next; prevNode->next = newNode; newNode->prev = prevNode; if (new_node->next != NULL) new_node->next->prev = new_node; }
|
在给定位置之前插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void insertBefore(Node* nextNode, int val) { if (nextNode == NULL) { cout << "the given next node cannot be NULL"; return; }
Node* newNode = new Node(val);
newNode->prev = nextNode->prev; nextNode->prev = newNode; newNode->next = nextNode;
if (newNode->prev != NULL) newNode->prev->next = newNode; else head = newNode; }
|
在DLL尾部插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| void insertAtTail(int val) { Node* newNode = new Node(val);
if (head == NULL) { newNode->prev = NULL; head = newNode; return; }
Node* last = head; while (last->next != NULL) { last = last->next; }
last->next = newNode; newNode->prev = last; }
|
合并链表
我们可以声明一个函数,直接对类操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| DoublyLinkedList mergeLists(DoublyLinkedList list1, DoublyLinkedList list2) { DoublyLinkedList mergeList; Node* current1 = list1.head; Node* current2 = list2.head; while(current1 != NULL || current2 != NULL) { if(current1 == NULL && current2 !=NULL) { mergeList.insertAtTail(current2->data); current2 = current2->next; } if(current2 == NULL && current1 !=NULL) { mergeList.insertAtTail(current1->data); current1 = current1->next; } if(current1 != NULL && current2 != NULL) { if(current1->data < current2->data) { mergeList.insertAtTail(current1->data); current1 = current1->next; } else { mergeList.insertAtTail(current2->data); current2 = current2->next; } } } return mergeList; }
|
打印
顺序打印
从头节点开始遍历,逐个打印
1 2 3 4 5 6 7 8 9
| void printList(DoublyLinkedList list) { Node* current = list.head; while (current != NULL) { cout << current->data << " "; current = current->next; } }
|
逆序打印
需要遍历到最后一个节点,再往前打印
1 2 3 4 5 6 7 8 9 10 11 12 13
| void printReverseList(DoublyLinkedList list) { Node* current = list.head; while (current->next != NULL) { current = current->next; } while(current != NULL) { cout << current->data << ' '; current = current->prev; } }
|
以上就是 使用C++中的类来完成对链表的基本操作
如果您发现有误,请在评论区留言或联系我