1 内存的分配和释放
链表题目里面涉及到删除元素的,要手动释放内存:
通常定义变量或者对象,编译器在编译时都可以根据该变量或对象的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间,这种内存分配被称为静态存储分配。
有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态内存分配。
所有动态存储分配都在堆区中进行。
new 和 delete:new 用来动态分配内存,delete 用来释放内存。
当程序运行到需要一个动态分配的变量或对象,必须向系统申请取得堆中的一块所需大小的存储空间,用于存储该变量或对象。当不再使用该变量或对象时,也就是它生命结束之时,要显式释放它所占用的存储空间,这样系统就能对该堆空间进行再分配,做到重复使用有限资源。
new运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字。
2移除链表元素
2.1 无虚拟头节点
![](https://i-blog.csdnimg.cn/blog_migrate/32171ee2cc6745fa499fc7a83d3cc42d.png)
//无虚拟头节点
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *cur = head;
//判断头节点
while(head != nullptr && head->val == val){
head = head->next;
}
//非头节点
while(cur != nullptr && cur->next != nullptr){
if(cur->next->val == val ){
ListNode *temp = cur->next;
cur->next = cur->next->next;
delete temp;
}else{
cur = cur->next;
}
}
return head;
}
};
2.2 有虚拟头节点
![](https://i-blog.csdnimg.cn/blog_migrate/d6d30741ce4c9a5f33b0c8b1556eda9c.png)
//设置虚拟头节点
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *dummyHead = new ListNode();
dummyHead->next = head; //将虚拟头节点链接在链表中
ListNode *cur = dummyHead;//临时节点为虚拟头节点:删除节点需要知道上一个节点
while(cur != nullptr && cur->next != nullptr){
if(cur->next->val == val ){
ListNode *temp = cur->next;
cur->next = cur->next->next;
delete temp;
}else{
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;;
}
};
3 设计链表
class MyLinkedList {
public:
//定义节点(成员,构造函数)
struct listNode{
int val;
listNode *next;
listNode():val(0),next(nullptr){}
listNode(int x):val(x),next(nullptr){}
};
public:
listNode *dummyNode;
int size;
public:
//初始化
MyLinkedList() {
dummyNode = new listNode();
size = 0;
}
//根据索引值查找对应节点值
int get(int index) {
//判断索引是否合理
if(index > size-1 || index < 0) return -1;
listNode *cur = dummyNode->next;
while(index--){
cur = cur->next;
}
return cur->val;
}
//在链表头添加节点
void addAtHead(int val) {
listNode *newNode = new listNode(val);//创建需要添加的新节点
newNode-> next = dummyNode->next;
dummyNode->next = newNode;
size++;//链表元素+1
}
//在链表尾部添加节点
void addAtTail(int val) {
listNode *newNode = new listNode(val);
listNode *cur = dummyNode;//不能是dummyNode->next,如果是空链表插入就会空指针异常
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newNode;
size++;
}
//根据索引添加元素
void addAtIndex(int index, int val) {
//判断index是否有效
if(index > size) return;
if(index < 0) index = 0;
listNode *newNode = new listNode(val);//构建新结点
listNode *cur = dummyNode;
while(index--){
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
size++;
}
//根据索引删除元素
void deleteAtIndex(int index) {
//判断index是否合理
if(index > size-1 || index < 0){
return ;
}
listNode *cur = dummyNode;
while(index--){
cur = cur->next;
}
listNode *temp = cur->next;
cur->next =cur->next->next;
delete temp;
size--;
}
// 打印链表
void printLinkedList() {
listNode *cur = dummyNode;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
};
/**
* 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);
*/
![](https://i-blog.csdnimg.cn/blog_migrate/b8f2d3ffd49ecf46450af1fb3d05cce0.png)
4 反转链表
4.1 双指针
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//空链表
if(head == nullptr) return head;
//非空链表
ListNode *pre = nullptr;
ListNode *cur = head;
while(cur != nullptr){
ListNode *temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
![](https://i-blog.csdnimg.cn/blog_migrate/b1e38afde967535b749bf37d4a4afd8a.png)
4.2 递归
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
//1.确定函数返回的类型以及参数
ListNode* reverse(ListNode* pre,ListNode* cur) {
//2.确认终止条件
if(cur == nullptr) return pre;
//3.单层逻辑
ListNode *temp = cur->next;
cur->next = pre;
return reverse(cur,temp);
}
ListNode* reverseList(ListNode* head) {
return reverse(nullptr,head);
}
};