这题做过,但是一点都想不起来了,十几天没做题,链表操作都忘了
ListNode* vir = new ListNode(0);
当前节点肯定不是空,所以判断的时候只需判断当前节点是否指向nullptr就可以了
/**
* 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* removeElements(ListNode* head, int val) {
// 法1. 使用虚拟头结点
ListNode* vir = new ListNode(0);
vir->next = head;
ListNode* cur = vir;
while (cur->next != nullptr) {
if (cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
head = vir->next;
delete vir;
return head;
// 法2,分为头结点和非头结点,分别删除
// //删除头结点
// while ((head != nullptr) && (head->val == val)) {
// ListNode* tmp = head;
// head = head->next;
// delete tmp;
// }
// ListNode* cur = head;
// while ((cur != nullptr) && (cur->next != nullptr)) {
// if (cur->next->val == val) {
// ListNode* tmp = cur->next;
// cur->next = cur->next->next;
// delete tmp;
// } else {
// cur = cur->next;
// }
// }
// return head;
}
};
如何构造一个链表?
类里还可以定义结构体?那类里能定义类嘛?
C++中的类可以定义新的类或者结构体。这种情况被称为嵌套类(Nested Class)。
我们可以在一个类中定义另一个类。这个嵌套类具有与普通类相同的成员,如变量和函数,但也有一些不同之处。嵌套类可以被私有、公有或受保护,可以是静态或非静态的,可以是虚拟的或非虚拟的。
下面是一个示例:
class OuterClass
{
public:
// 嵌套类
class InnerClass
{
public:
void display()
{
cout << "This is Inner Class" << endl;
}
};
};
int main()
{
//创建外部类对象
OuterClass outer;
// 在外部类中调用内部类方法
OuterClass::InnerClass inner_obj;
inner_obj.display();
return 0;
}
输出:
This is Inner Class
在这里,我们定义了一个名为 OuterClass 的类,并在其中定义了一个名为 InnerClass 的嵌套类。InnerClass 中有一个名为 display 的函数,它将一个消息输出到屏幕上。
在主函数中,我们首先创建了 OuterClass 的对象 outer,然后创建了它的嵌套类 InnerClass 的对象 inner_obj,并使用该对象调用 display 函数,显示消息 “This is Inner Class”。
_dummyHead 是一个指向链表头结点的指针,它是一个 LinkedNode* 类型的变量。在这个构造函数中,我们初始化了 _dummyHead,将它指向一个空的 LinkedNode 结点。
_size 是链表元素的数量,它是一个整数类型的变量。在构造函数中,我们将 _size 初始化为 0,因为此时链表中还没有元素。
class MyLinkedList {
public:
// 定义链表节点结构体
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr) {}
};
// 初始化链表
MyLinkedList() {
_dummyHead = new LinkedNode(0); //_dummyHead 是一个指向链表头结点的指针,它是一个 LinkedNode* 类型的变量。始在这个构造函数中,我们初化了 _dummyHead,将它指向一个空的 LinkedNode 结点。
_size = 0;
}
// 获取下标为index的元素
int get(int index) {
if (index > (_size - 1) || index < 0) {
return -1;
}
LinkedNode* cur = _dummyHead->next; //指向头结点
while (index--) {
cur = cur->next;
}
return cur->val;
}
//
void addAtHead(int val) {
LinkedNode* newNode = new LinkedNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
void addAtTail(int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while (cur->next != nullptr) {
cur = cur->next;
}
cur->next = newNode;
_size++;
}
void addAtIndex(int index, int val) {
if (index > _size) return;
if (index < 0) index = 0;
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur =_dummyHead;
while (index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
void deleteAtIndex(int index) {
if (index >= _size || index < 0) {
return;
}
LinkedNode* cur = _dummyHead;
while (index--) {
cur = cur->next;
}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}
// 打印链表
void printLinkedList() {
LinkedNode* cur = _dummyHead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
private:
int _size;
LinkedNode* _dummyHead;
};
/**
* 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);
*/
遍历链表,用一个栈存链表中的每个元素,然后重新从链表投挨个节点赋值
这样可以双指针啊,我先用栈实现吧,双指针得归纳一下了。
在你的例子中,ListNode* tmp;定义了一个指向ListNode类型的指针变量tmp,但它没有指向任何有效的内存空间。如果你尝试在使用tmp之前对其进行操作(例如访问其值或在其上进行解引用),可能会导致未定义的行为。
为了避免悬空指针的问题,你可以选择在定义指针时将其初始化为nullptr,表示它不指向任何有效的内存空间,例如:ListNode* tmp = nullptr;。然后,你可以在后续的代码中为该指针分配内存空间或将其指向有效的对象。
法2:递归
暂时没动手实现;
法3:用栈实现(自己最先想到)
// 我的
ListNode* cur2 = head;
while (!stk.empty()) {
cur2->val = stk.top();
cur2 = cur2->next;
stk.pop();
}
cur2->next = nullptr;
return head;
//正确的
ListNode* newHead = new ListNode(stk.top()); // 倒置之后的链表的头结点应该是原链表尾节点,所以先取出栈顶元素作为新头结点
ListNode* cur2 = newHead; // 从新的头结点开始
stk.pop(); // 把新的头结点从栈中剔除
while (!stk.empty()) {
ListNode* newNode = new ListNode(stk.top()); // 栈顶元素作为新节点值
cur2->next = newNode; // 指向新节点
cur2 = cur2->next; // 移动指针到新节点
stk.pop(); // 弹出栈顶元素
}
cur2->next = nullptr; // 修改尾结点的next指针
return newHead; // 返回新链表的头结点
#include
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr) { //如果链表为空或只有一个节点,直接返回原链表;反转后仍为同一链表
return head;
}
stack<int> stk; // 栈需要指定模板类型,这里是存储int的单链表
ListNode* cur = head;
while (cur != nullptr) {
stk.push(cur->val); // 将链表的数值依次入栈
cur = cur->next;
}
ListNode* newHead = new ListNode(stk.top()); // 倒置之后的链表的头结点应该是原链表尾节点,所以先取出栈顶元素作为新头结点
ListNode* cur2 = newHead; // 从新的头结点开始
stk.pop(); // 把新的头结点从栈中剔除
while (!stk.empty()) {
ListNode* newNode = new ListNode(stk.top()); // 栈顶元素作为新节点值
cur2->next = newNode; // 指向新节点
cur2 = cur2->next; // 移动指针到新节点
stk.pop(); // 弹出栈顶元素
}
cur2->next = nullptr; // 修改尾结点的next指针
return newHead; // 返回新链表的头结点
}
};
ListNode *tmp 与ListNode* tmp 是等价的
在C++中,**内存泄漏(Memory Leak)**是指在程序运行过程中,动态分配的内存没有被正确释放或回收的情况。当内存泄漏发生时,程序无法再访问或使用被泄漏的内存块,导致系统中的可用内存逐渐减少,直到最终耗尽可用内存,程序可能会崩溃或表现出异常的行为。
内存泄漏通常发生在以下情况下:
int* ptr = new int; // 没有释放ptr指向的内存,造成内存泄漏
void function() {
int* ptr = new int;
ptr = nullptr; // ptr丢失对动态内存的引用,无法释放内存
}
class Node {
public:
std::shared_ptr<Node> next;
};
std::shared_ptr<Node> node1 = std::make_shared<Node>();
std::shared_ptr<Node> node2 = std::make_shared<Node>();
node1->next = node2;
node2->next = node1; // 循环引用,导致两个节点无法被释放
内存泄漏会导致程序占用的内存越来越多,最终可能耗尽系统资源。为避免内存泄漏,需要确保在动态分配内存后及时释放,并避免循环引用等情况。使用智能指针、RAII(资源获取即初始化)等技术可以帮助自动管理内存,减少内存泄漏的风险。此外,内存泄漏检测工具和良好的代码设计和测试也能帮助发现和解决内存泄漏问题。