文章目录
- 一、题目
- 二、设计链表
- 三、完整代码
所有的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) {
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); // 虚假头结点
_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) {
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[] = { 6, 7, 2, 0, 4 };
int len = sizeof(arr) / sizeof(int);
MyLinkedList m1;
m1.addAtIndex(1, 0);
m1.LinkListPrint("打印链表:");
int val1 = m1.get(0);
cout << "目标索引的值:" << val1 << endl;
system("pause");
return 0;
}
end