文章目录
- 一、题目
- 二、设计链表
- 三、完整代码
所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。
一、题目
二、设计链表
思路分析:这里我将的成员函数放在类外实现了,这样链表类看起来更加简洁,方便大家学习链表的结构,主要包含:节点类结构体,构造函数(构造函数也可以放在类外实现),成员函数和成员变量。类的成员函数实现主要有两种,一种是类内实现,一种是类外实现,类外实现需要在类内写声明,然后在类外写实现。构造函数初始化一个虚假头结点和链表大小。关于虚假头结点,可以参考【算法与数据结构】203、LeetCode移除链表元素。
链表类如下:
// 链表类
class MyLinkedList {
public: // 定义链表节点类结构体struct LinkNode {int val;LinkNode* next;LinkNode() : val(0), next(NULL) {};LinkNode(int input_val) : val(input_val), next(NULL) {};LinkNode(int input_val, LinkNode* input_next) : val(input_val), next(input_next) {};};// 构造函数MyLinkedList() {_FakeNode = new LinkNode(0); // 虚假头结点_size = 0;}
// 成员函数int get(int index);void addAtHead(int val);void addAtTail(int val);void addAtIndex(int index, int val);void deleteAtIndex(int index);void ChainGenerator(int arr[], int len);void LinkListPrint(string str);
// 成员变量
private:int _size;LinkNode* _FakeNode;
};
讲完整体构造,然后将各个部分。
首先是get函数:进入链表首先判断index是否合法,然后链表从虚假头结点出发,利用index,当找到目标索引时,cur就指向这个值,index自减归于0退出循环。
int MyLinkedList::get(int index) { if (index > (_size - 1) || index < 0) return -1;LinkNode* cur = _FakeNode->next; // 头结点while (index--) {cur = cur->next;}return cur->val;
}
addAtHead函数:这个函数比较简单,我们新建一个节点,指向虚节点的下一个节点(也就是插入之前的头结点),然后让虚节点指向新建节点,最后链表大小+1。
void MyLinkedList::addAtHead(int val) {LinkNode* pNewNode = new LinkNode(val, _FakeNode->next);_FakeNode->next = pNewNode;_size++;
}
addAtTail函数:addTail函数需要遍历这个链表,找到尾节点,复杂度是 O ( n ) O(n) O(n),让尾节点指向新建节点即可。
void MyLinkedList::addAtTail(int val) {LinkNode* pNewNode = new LinkNode(val);LinkNode* cur = _FakeNode;while (cur->next != NULL) {cur = cur->next;}cur->next = pNewNode;_size++;
}
addAtIndex函数:前两个函数都可以用这个函数实现,在这个函数中,首先根据题目条件判断index是否合法,令cur指针等于虚节点,同样使用index找到插入位置的上一个节点,然后就是链表的插入操作。
void MyLinkedList::addAtIndex(int index, int val) { if (index > _size) return;if (index < 0) index = 0;LinkNode* cur = _FakeNode; // 虚结点 // 需要断开上一一个阶段的链接,从插入位置的上一个索引开始处理while (index--) {cur = cur->next;}LinkNode* pNewNode = new LinkNode(val, cur->next);cur->next = pNewNode;_size++;
}
deleteAtIndex函数:这个函数可以参考【算法与数据结构】203、LeetCode移除链表元素。
void MyLinkedList::deleteAtIndex(int index) { if (index > (_size - 1) || index < 0) return;LinkNode* cur = _FakeNode; // 头结点// 需要断开上一一个阶段的链接while (index--) {cur = cur->next;}LinkNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;tmp = NULL;_size--;
}
ChainGenerator函数和LinkListPrint函数:除了题目要求的函数以外,我还写了数组生成链表函数,以及链表打印函数。这两个函数在main函数中调用,方便调试。
void MyLinkedList::ChainGenerator(int arr[], int len) {if (_FakeNode->next != NULL) return;LinkNode* head = new LinkNode(arr[0], NULL);LinkNode* p = head;for (int i = 1; i < len; i++) {LinkNode* pNewNode = new LinkNode(arr[i], NULL);p->next = pNewNode; // 上一个节点指向这个新建立的节点p = pNewNode; // p节点指向这个新的节点}_FakeNode->next = head;_size = len;
}
void MyLinkedList::LinkListPrint(string str) {cout << str << endl;LinkNode* cur = _FakeNode;while (cur->next != NULL) {cout << cur->next->val << ' ';cur = cur->next;}cout << endl;
}
三、完整代码
# include <iostream>
using namespace std;// 链表类
class MyLinkedList {
public: // 定义链表节点类结构体struct LinkNode {int val;LinkNode* next;LinkNode() : val(0), next(NULL) {};LinkNode(int input_val) : val(input_val), next(NULL) {};LinkNode(int input_val, LinkNode* input_next) : val(input_val), next(input_next) {};};// 构造函数MyLinkedList() {_FakeNode = new LinkNode(0,NULL); // 虚假头结点_size = 0;}
// 成员函数int get(int index);void addAtHead(int val);void addAtTail(int val);void addAtIndex(int index, int val);void deleteAtIndex(int index);void ChainGenerator(int arr[], int len);void LinkListPrint(string str);
// 成员变量
private:int _size;LinkNode* _FakeNode;
};// 类外实现链表的成员函数
int MyLinkedList::get(int index) { if (index > (_size - 1) || index < 0) return -1;LinkNode* cur = _FakeNode->next; // 头结点while (index--) {cur = cur->next;}return cur->val;
}void MyLinkedList::addAtHead(int val) {LinkNode* pNewNode = new LinkNode(val, _FakeNode->next);_FakeNode->next = pNewNode;_size++;
}void MyLinkedList::addAtTail(int val) {LinkNode* pNewNode = new LinkNode(val);LinkNode* cur = _FakeNode;while (cur->next != NULL) {cur = cur->next;}cur->next = pNewNode;_size++;
}void MyLinkedList::addAtIndex(int index, int val) { if (index > _size) return;if (index < 0) index = 0;LinkNode* cur = _FakeNode; // 虚结点 // 需要断开上一一个阶段的链接,从插入位置的上一个索引开始处理while (index--) {cur = cur->next;}LinkNode* pNewNode = new LinkNode(val, cur->next);cur->next = pNewNode;_size++;
}void MyLinkedList::deleteAtIndex(int index) { if (index > (_size - 1) || index < 0) return;LinkNode* cur = _FakeNode; // 头结点// 需要断开上一一个阶段的链接while (index--) {cur = cur->next;}LinkNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;tmp = NULL;_size--;
}void MyLinkedList::ChainGenerator(int arr[], int len) {if (_FakeNode->next != NULL) return;LinkNode* head = new LinkNode(arr[0], NULL);LinkNode* p = head;for (int i = 1; i < len; i++) {LinkNode* pNewNode = new LinkNode(arr[i], NULL);p->next = pNewNode; // 上一个节点指向这个新建立的节点p = pNewNode; // p节点指向这个新的节点}_FakeNode->next = head;_size = len;
}void MyLinkedList::LinkListPrint(string str) {cout << str << endl;LinkNode* cur = _FakeNode;while (cur->next != NULL) {cout << cur->next->val << ' ';cur = cur->next;}cout << endl;
}int main()
{int arr[] = { 2, 3};int len = sizeof(arr) / sizeof(int);MyLinkedList m1;m1.ChainGenerator(arr, len);m1.LinkListPrint("打印链表:");m1.addAtHead(1);m1.addAtTail(5);m1.LinkListPrint("打印链表:");m1.addAtIndex(3, 4);m1.addAtIndex(5, 666);m1.LinkListPrint("打印链表:");m1.deleteAtIndex(5);m1.LinkListPrint("打印链表:");int val1 = m1.get(0);cout << "目标索引的值:" << val1 << endl;system("pause");return 0;
}
end