赞
踩
记录七:力扣【707. 设计链表】
完成链表索引,增删操作。
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性: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); //头部添加元素1
myLinkedList.addAtTail(3); //尾部添加元素3
myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
myLinkedList.get(1); // 返回 第一个节点,元素值为2
myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
myLinkedList.get(1); // 返回 第一个节点,元素值为3
class MyLinkedList { private: ListNode* head = nullptr; public: MyLinkedList() { ListNode* head = nullptr; } int get(int index) { ListNode* cur = head; int num = 0;//计数 while( cur != nullptr){ if(num == index){ return cur->val; } cur = cur->next; num++; } return -1; } void addAtHead(int val) { if(head == nullptr){ head = new ListNode(val); return; }else{ ListNode* node = new ListNode(val); node->next = head; head = node; return; } } void addAtTail(int val) { ListNode* cur = head; if(cur == nullptr){ ListNode* node = new ListNode(val); head = node; return; } while(cur != nullptr){ if(cur->next == nullptr){ ListNode* node = new ListNode(val); cur->next = node; break; }else{ cur = cur->next; } } } void addAtIndex(int index, int val) { ListNode *newnode = new ListNode(val); int num = 0; ListNode* dummy_node = new ListNode(0,head); ListNode* cur = dummy_node; while(cur!= nullptr ){ if(num == index){ newnode->next = cur->next; cur->next = newnode; break; }else{ cur = cur->next; num++; } } head = dummy_node->next; delete dummy_node; } void deleteAtIndex(int index) { ListNode* dummy_node = new ListNode(0,head); ListNode* cur = dummy_node; int num = 0; while(cur != nullptr && cur->next != nullptr){ if(num == index){ ListNode* tmp = cur->next; cur->next = cur->next->next; delete tmp; break; }else{ cur = cur->next; num++; } } head = dummy_node->next; delete dummy_node; } }; //具体实例化方式和调用方式: /** * Your MyLinkedList object will be instantiated and called as such: * MyLinkedList* obj = new MyLinkedList(); * int param_1 = obj->get(index); * obj->addAtHead(val); * obj->addAtTail(val); * obj->addAtIndex(index,val); * obj->deleteAtIndex(index); */
(1)构造函数
MyLinkedList() {
ListNode* head = nullptr;
}
调用 MyLinkedList myLinkedList = new MyLinkedList(); //创建对象 时,需要一个头节点,是链表的入口,所以成员ListNode* head头指针应该得到初始化。一开始创建一个空链表,没有节点,所以ListNode* head = nullptr;赋为空。
(2)获取元素
int get(int index) {
ListNode* cur = head;
int num = 0;//计数
while( cur != nullptr){
if(num == index){
return cur->val;
}
cur = cur->next;
num++;
}
return -1;
}
所以逻辑正确。
(3)添加头元素
void addAtHead(int val) {
if(head == nullptr){
head = new ListNode(val);
return;
}else{
ListNode* node = new ListNode(val);
node->next = head;
head = node;
return;
}
}
但是我发现:在else逻辑下,没有head->,说明即使head为空,我也没有访问空指针。那么可以合二为一,无需分开讨论,改进:
void addAtHead(int val) {
// if(head == nullptr){
// head = new ListNode(val);
// return;
// }else{
ListNode* node = new ListNode(val);
node->next = head;
head = node;
return;
//}
}
(4)在链表尾部添加元素
void addAtTail(int val) { ListNode* cur = head; if(cur == nullptr){ ListNode* node = new ListNode(val); head = node; return; } while(cur != nullptr){ if(cur->next == nullptr){ ListNode* node = new ListNode(val); cur->next = node; break; }else{ cur = cur->next; } }
先创建一个要添加的节点:ListNode* node = new ListNode(val);
找到cur->next == nullptr说明到达链表尾部。修改cur->next = node;
因为用到cur->next,说明cur不能为空。所以我初始考虑cur==nullptr情况,即空链表时:
if(cur == nullptr){
ListNode* node = new ListNode(val);
head = node;
return;
}
再while(cur != nullptr),找到链表尾部。
(5)在下标index之前添加元素
void addAtIndex(int index, int val) { ListNode *newnode = new ListNode(val); int num = 0; ListNode* dummy_node = new ListNode(0,head); ListNode* cur = dummy_node; while(cur!= nullptr ){ if(num == index){ newnode->next = cur->next; cur->next = newnode; break; }else{ cur = cur->next; num++; } } head = dummy_node->next; delete dummy_node; }
改进:
void addAtIndex(int index, int val) { ListNode *newnode = new ListNode(val); int num = 0; ListNode* dummy_node = new ListNode(0,head); ListNode* cur = dummy_node; while(cur!= nullptr ){ if(num == index){ newnode->next = cur->next; cur->next = newnode; break; }else{ cur = cur->next; num++; } } if(num < index){ //注意这里。没用上newnode,需要释放本次调用创建的内存。 delete newnode; } head = dummy_node->next; delete dummy_node; }
(6)在下标index之前删除元素
void deleteAtIndex(int index) { ListNode* dummy_node = new ListNode(0,head); ListNode* cur = dummy_node; int num = 0; while(cur != nullptr && cur->next != nullptr){ if(num == index){ ListNode* tmp = cur->next; cur->next = cur->next->next; delete tmp; break; }else{ cur = cur->next; num++; } } head = dummy_node->next; delete dummy_node; } };
思路:用虚拟头节点统一删除操作。cur需要停在删除目标之前。
两个地方:一、添加头元素;二、在下标index之前添加元素
class MyLinkedList { private: ListNode* head = nullptr; public: MyLinkedList() { ListNode* head = nullptr; } int get(int index) { ListNode* cur = head; int num = 0;//计数 while( cur != nullptr){ if(num == index){ return cur->val; } cur = cur->next; num++; } return -1; } void addAtHead(int val) { //多余if判断 // if(head == nullptr){ // head = new ListNode(val); // return; // }else{ ListNode* node = new ListNode(val); node->next = head; head = node; return; //} } void addAtTail(int val) { ListNode* cur = head; if(cur == nullptr){ ListNode* node = new ListNode(val); head = node; return; } while(cur != nullptr ){ if(cur->next == nullptr){ ListNode* node = new ListNode(val); cur->next = node; break; }else{ cur = cur->next; } } } void addAtIndex(int index, int val) { ListNode *newnode = new ListNode(val); int num = 0; ListNode* dummy_node = new ListNode(0,head); ListNode* cur = dummy_node; while(cur!= nullptr ){ if(num == index){ newnode->next = cur->next; cur->next = newnode; break; }else{ cur = cur->next; num++; } } if(num < index){ //这里增加一段if delete newnode; } head = dummy_node->next; delete dummy_node; } void deleteAtIndex(int index) { ListNode* dummy_node = new ListNode(0,head); ListNode* cur = dummy_node; int num = 0; while(cur != nullptr && cur->next != nullptr){ if(num == index){ ListNode* tmp = cur->next; cur->next = cur->next->next; delete tmp; break; }else{ cur = cur->next; num++; } } head = dummy_node->next; delete dummy_node; } }; /** * Your MyLinkedList object will be instantiated and called as such: * MyLinkedList* obj = new MyLinkedList(); * int param_1 = obj->get(index); * obj->addAtHead(val); * obj->addAtTail(val); * obj->addAtIndex(index,val); * obj->deleteAtIndex(index); */
(1)虚拟头节点
我是在函数操作(5)(6)在index之前添加/删除元素才考虑到dummy_node,在函数方便使用;
参考教程:直接class MyLinkedList中定义一个dummy_node,所有函数都可以用dummy_node操作。
(2)index
我没有先判断index在不在范围,而是先操作链表,如果index不在范围,最后while结束即可;
参考教程:定义int _size;可以先判断index在不在范围,不在范围就直接return。不用多余浪费时间循环链表。
总结:参考的方法更加统一方便。
我在public中多加了 ListNode* head;创建对象后,可以获取到链表的head,但是dummy_node是隐藏的(在private中)。
//单链表 class MyLinkedList { private: ListNode* dummy_node; int _size;//链表节点数量 public: //struct ListNode{ // int val; // ListNode* next; // ListNode():val(0),next(nullptr){} // ListNode(int i):val(i),next(nullptr){} // ListNode(int i,ListNode* next):val(i),next(next){} //}; ListNode* head;//可以加一个头节点 MyLinkedList() { //空链表 dummy_node = new ListNode(); head = dummy_node->next; _size = 0; } int get(int index) { if(index < 0 || index >= _size){ //大于等于_size,index才合法。 return -1; } ListNode* cur = dummy_node->next; while(index--){ //先判断,后-- cur = cur->next; } return cur->val; } void addAtHead(int val) { ListNode* newnode = new ListNode(val); newnode->next = head; dummy_node->next = newnode; head = dummy_node->next; // 更改head的位置,始终是dummy_node->next _size++; } void addAtTail(int val) { ListNode* newnode = new ListNode(val); ListNode* cur = dummy_node; while(cur->next != nullptr){ cur = cur->next; } cur->next = newnode; _size++; } void addAtIndex(int index, int val) { if(index < 0 || index > _size){ //大于size,当等于size时,可以在尾部添加。 return; } ListNode* newnode = new ListNode(val); ListNode* cur = dummy_node; int num = index; while(num--){ cur=cur->next; } newnode->next = cur->next; cur->next = newnode; if(index == 0){ //head需要改变 head = dummy_node->next; } _size++; } void deleteAtIndex(int index) { if(index < 0 || index >= _size){ //_size是数量,所以最后一个有效的下标是 _size-1 return; } ListNode* cur = dummy_node; int num = index; //因为要用index判断head有没有改变。所以给num while(num--){ cur = cur->next; } ListNode* tmp = cur->next; cur->next = cur->next->next; delete tmp; if(index==0){ //删除0号,所以head改变。 head = dummy_node->next; } _size--; } }; /** * Your MyLinkedList object will be instantiated and called as such: * MyLinkedList* obj = new MyLinkedList(); * int param_1 = obj->get(index); * obj->addAtHead(val); * obj->addAtTail(val); * obj->addAtIndex(index,val); * obj->deleteAtIndex(index); */
链表构建最好有一个虚拟头节点。
(欢迎指正,转载表明出处)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。