1.题目
707. 设计链表 - 力扣(LeetCode)
单链表中的节点应该具备两个属性:
val
和next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。如果是双向链表,则还需要属性
prev
以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。实现
MyLinkedList
类:
MyLinkedList()
初始化MyLinkedList
对象。int get(int index)
获取链表中下标为index
的节点的值。如果下标无效,则返回-1
。void addAtHead(int val)
将一个值为val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为val
的节点插入到链表中下标为index
的节点之前。如果index
等于链表的长度,那么该节点会被追加到链表的末尾。如果index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为index
的节点。示例:
输入 ["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"] [[], [1], [3], [1, 2], [1], [1], [1]] 输出 [null, null, null, null, 2, null, 3] 解释 MyLinkedList myLinkedList = new MyLinkedList(); myLinkedList.addAtHead(1); myLinkedList.addAtTail(3); myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3 myLinkedList.get(1); // 返回 2 myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3 myLinkedList.get(1); // 返回 3提示:
0 <= index, val <= 1000
- 请不要使用内置的 LinkedList 库。
- 调用
get
、addAtHead
、addAtTail
、addAtIndex
和deleteAtIndex
的次数不超过2000
。
2.代码
直接套用+修改C26.【C++ Cont】动态内存管理和面向对象的方式实现链文章的代码
struct Node
{
int val;
struct Node* next;
};
class MyLinkedList
{
public:
Node* phead;
Node* ptail;
int length;
Node* BuySLTNode(int x)//新建节点
{
Node* newnode = new Node;
newnode->val = x;
newnode->next = nullptr;
return newnode;
}
MyLinkedList()//构造函数,自动调用
{
phead = nullptr;
ptail = nullptr;
length = 0;
}
int get(int index)
{
if (length == 0 || index >= length)
return -1;
int tmp = 0;
Node* cur = phead;
while (tmp != index)
{
cur = cur->next;
tmp++;
}
return cur->val;
}
void addAtHead(int val)
{
Node* newnode = BuySLTNode(val);
if (phead == nullptr)
{
phead = ptail = newnode;
}
else
{
newnode->next = phead;
phead = newnode;//不用改动ptail
}
length++;
}
void addAtTail(int val)
{
Node* newnode = BuySLTNode(val);
if (phead == nullptr)
{
ptail = phead = newnode;//如果是第一次插入需要同时更新首尾指针
}
else
{
ptail->next = newnode;
ptail = ptail->next;
}
length++;
}
void addAtIndex(int index, int val)
{
if (index > length)
return;
if (index == length)
{
addAtTail(val);
return;
}
if (index == 0)
{
addAtHead(val);
return;
}
Node* newnode = BuySLTNode(val);
Node* cur = phead;
int tmp = 0;
while (tmp < index - 1)
{
cur = cur->next;
tmp++;
}
newnode->next = cur->next;
cur->next = newnode;
length++;
}
void SLTPopBack()//尾删节点
{
if (phead == nullptr)
{
return;
}
Node* tmp = phead;
if (phead->next == nullptr)
{
delete phead;
ptail = phead = nullptr;//删除最后一个节点,注意将首尾指针都置为空
length--;
return;
}
while (tmp->next != ptail)//寻找尾节点前面的节点
{
tmp = tmp->next;
}
delete ptail;
ptail = tmp;
ptail->next = nullptr;
tmp = nullptr;
length--;
}
void SLTPopFront()//头删节点
{
if (phead == nullptr)
{
return;
}
if (phead->next == nullptr)
{
ptail = nullptr;//链表只剩一个节点,ptail要手动置空
}
Node* tmp = phead;
phead = tmp->next;
delete tmp;
tmp = nullptr;
length--;
}
void deleteAtIndex(int index)
{
if (index >= length || length == 0)
return;
if (index == length - 1)
{
SLTPopBack();
return;
}
if (index == 0)
{
SLTPopFront();
return;
}
Node* cur = phead;
int tmp = 0;
while (tmp < index - 1)//index-1>0
{
cur = cur->next;
tmp++;
}
Node* indexnode = cur->next;
cur->next = indexnode->next;
delete indexnode;
indexnode = nullptr;
length--;
}
};
注意点:
1.每一种情况返回前思考需不需要length++或者length--
★以SLTPopBack为例,有两个地方需要length--!!!(此处debug 1h 才看出来问题= =)
2.几个特殊情况的处理
get:链表长为0或者index>=length的,一律返回-1
addAtIndex:index>length不作处理,index==length按题意理解为尾插,index==0为头插
deleteAtIndex:链表长为0或者index>=length的,一律不处理;index == length - 1尾删;index == 0头删