移除链表元素
#include<iostream>
using namespace std;
struct linknote
{
int val;
linknote* next;
linknote(int x) :next(nullptr), val(x)
{
}
};
void shanchu(linknote* start,int target)
{
linknote* p = new linknote(0);
p->next = start;
if (start == nullptr)
{
cout << "nothing没有元素" << endl;
return;
}
while (p->next != nullptr)
{
if (p->next->val == target)
{
p->next = p->next->next;//我认为这个地方最好的理解方式就是前值后 让左面的值指向右面的值
break;
}
else
{
p = p->next;
}
}
}
void xianshi(linknote* start2)
{
while (start2 != nullptr)
{
cout << start2->val << " ";
}
}
int main()
{
linknote* p1 = new linknote(3);
linknote* p2 = new linknote(4);
linknote* p3 = new linknote(5);
p1->next = p2;
p2->next = p3;
shanchu(p1,3);
xianshi(p1);
}
///* 删除链表的节点 n0 之后的首个节点 */
//void remove(ListNode* n0) {
// if (n0->next == nullptr)
// return;
// // n0 -> P -> n1
// ListNode* P = n0->next;
// ListNode* n1 = P->next;
// n0->next = n1;
// // 释放内存
// delete P;
//
// ListNode* P ;
// n0->next;=p;
//
//}
在链表操作中,直接覆盖节点值并不等于删除节点。删除节点不仅需要从链表中移除,还需要正确释放其内存,以防止内存泄漏
正确的做法是在移动指针之前保存当前节点的指针,然后在移动指针之后删除当前节点。
在 shanchu
函数中,不需要删除 cur
的原因是 cur
只是一个指向链表中某个节点的指针变量,它本身并不占用动态内存。我们只需要删除动态分配的节点,指针变量 cur
是局部变量,会在函数结束后自动销毁,不需要手动删除。
这里的 linknote*& start
表示传递的是 linknote*
类型的引用,即指针的引用。
#include<iostream>
using namespace std;
struct linknote
{
linknote* next;
int val;
linknote(int x):next(nullptr),val(x){}
};
void shanchu(linknote* &start, int target)
{
linknote* p = new linknote(0);
p->next = start;
linknote* cur = p;
while (cur->next != nullptr)
{
if (cur->next->val == target)
{
linknote* temp = cur->next;
cur->next = cur->next->next;
delete temp;
break;
}
else
{
cur = cur->next;
}
}
start = p->next;
delete p;
}
void xianshi(linknote* start2)
{
while (start2 != nullptr)
{
cout << start2->val << " ";
start2 = start2->next;
}
}
int main()
{
linknote* p1 = new linknote(3);
linknote* p2 = new linknote(4);
linknote* p3 = new linknote(5);
p1->next = p2;
p2->next = p3;
xianshi(p1);
shanchu(p1, 3);
cout << endl;
xianshi(p1);
while (p1!=nullptr)
{
linknote* temp = p1;
p1 = p1->next;
delete temp;
}
}
我个人认为还是应该写带虚拟头节点的,这样更方便做一些处理。
设计链表
以下这个报错是设计链表里面的
一下这个代码虽然错误百出 但是只有知道每一步的错误原因,才能更好的理解链表。
这个代码的具体找错,我会在以后在小红书上学习直播的时候讲
#include<iostream>
using namespace std;
struct linknote
{
linknote* next;
int val;
linknote(int x) :next(nullptr), val(x) {}
};
int re_long(linknote* start)
{
int l_ong = 0;
while (start != nullptr)
{
l_ong++;
start = start->next;
}
return l_ong;
}
void get(int index, int n, linknote* start)
{
if (index<0 || index>n)
{
cout<< "不符合查询范围";
return;
}
while (index--)
{
start = start->next;
}
cout << start->val;
}
void addbegin(linknote*& start, int vall)
{
linknote* cur = new linknote(vall);
cur->next = start;
while (cur != nullptr)
{
cout << cur->val << " ";
cur = cur->next;
}
//delete cur;在你最初的代码中,是在打印链表节点后删除 cur 指针的,
// 但是由于在打印链表节点时,cur 指针已经指向了链表中的下一个节点,所以实际上你并没有删除链表的头节点,
// 而是删除了链表的第二个节点,这样会导致链表头节点丢失,无法正确访问整个链表。
}
void addend(linknote*& start, int vall)
{
linknote* cur = new linknote(vall);
//if (start == nullptr)
//{
// start= cur;
// return;
//}
linknote* note = start;
while (note->next != nullptr)
{
note = note->next;
}
note->next = cur;
while (start != nullptr)
{
cout << start->val << " ";
start = start->next;
}
}
void tianjia(linknote*& start, int index, int n,int vall)
{
if (index == n)
{
addend(start, vall);
}
else if (index > n)
{
cout << "impossible";
}
else if (index < 0)
{
addbegin(start, vall);
}
else
{
linknote* cur = start;
/* while (index--)
{
cur = cur->next;
}*/
for (int i = 0; i < index; ++i)
{
if (cur == nullptr || cur->next == nullptr) {
cout << "Error: n is out of bounds of the list length." << endl;
return; // Exit the function or handle the error as needed
}
cur = cur->next;
}
linknote* cha = new linknote(vall);
cha->next = cur->next;
cur->next = cha;
while (start != nullptr)
{
cout << start->val << " ";
start = start->next;
}
linknote* cur = start;
// 遍历链表到指定索引位置
for (int i = 0; i < index; ++i)
{
if (cur == nullptr || cur->next == nullptr) {
cout << "Error: index is out of bounds of the list length." << endl;
return; // 退出函数或按需处理错误
}
cur = cur->next;
}
linknote* cha = new linknote(vall);
cha->next = cur->next;
cur->next = cha;
// 使用临时指针打印链表,避免修改 start
linknote* temp = start;
while (temp != nullptr)
{
cout << temp->val << " ";
temp = temp->next;
}
}
}
void shanchu(linknote*& start, int index,int n)
{
if (index > n || index < 0)
{
cout << "impossible";
}
else
{
linknote* cur = start;
while (index--)
{
cur = cur->next;
}
cur = cur->next;
}
while (start != nullptr)
{
cout << start->val << " ";
start = start->next;
}
}
void shanchu(linknote*& start, int index, int n)
{
if (index >= n || index < 0)
{
cout << "impossible" << endl;
return; // 立即返回避免继续执行
}
linknote* cur = start;
//如果要删除的是第一个节点
if (index == 0)
{
linknote* toDelete = start;
start = start->next;
delete toDelete;
}
else
{
// 遍历到 index 位置的前一个节点
for (int i = 0; i < index - 1; ++i)
{
cur = cur->next;
}
// 删除节点
linknote* toDelete = cur->next;
cur->next = cur->next->next;
delete toDelete;
}
// 使用临时指针打印链表,避免修改 start
linknote* temp = start;
while (temp != nullptr)
{
cout << temp->val << " ";
temp = temp->next;
}
cout << endl; // 输出换行符
}
int main()
{
linknote* p1 = new linknote(2);
linknote* p2 = new linknote(3);
linknote* p3 = new linknote(4);
p1->next = p2;
p2->next = p3;
int n = re_long(p1);
cout << "get" << endl;
get(1, n, p1);
cout << endl << "begin" << endl;
addbegin(p1, 1);
cout << endl << "end" << endl;
addend(p1, 6);
cout << "tianjia" << endl;
//tianjia(p1, 1, n, 0);
cout << endl << " shanchu" << endl;
/*shanchu(p1, 3, n);*/
}
请仔细看下面这个再类中又用到了结构体
这个是标准答案
#include <iostream>
using namespace std;
class MyLinkedList {
public:
// 定义链表节点结构体
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val) : val(val), next(nullptr) {}
};
// 初始化链表
MyLinkedList() {
_dummyHead = new LinkedNode(0); // 这里定义的头结点是一个虚拟头结点,而不是真正的链表头结点
_size = 0;
}
// 获取到第index个节点数值,如果index是非法数值直接返回-1,注意index是从0开始的,第0个节点就是头结点
int get(int index) {
if (index > (_size - 1) || index < 0) {
return -1;
}
LinkedNode* cur = _dummyHead->next;
while (index--) { // 如果--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++;
}
// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果index大于链表的长度,则返回空
// 如果index小于0,则在头部插入节点
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++;
}
// 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
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;
//delete命令指示释放了tmp指针原本所指的那部分内存,
//被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
//如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
//如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
tmp = nullptr;
_size--;
}
// 打印链表
void printLinkedList() {
LinkedNode* cur = _dummyHead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
private:
int _size;
LinkedNode* _dummyHead;
};
int main() {
MyLinkedList linkedList;
linkedList.addAtHead(1);
linkedList.printLinkedList(); // 输出: 1
linkedList.addAtTail(3);
linkedList.printLinkedList(); // 输出: 1 3
linkedList.addAtIndex(1, 2); // 链表变为1->2->3
linkedList.printLinkedList(); // 输出: 1 2 3
cout << linkedList.get(1) << endl; // 返回2
linkedList.deleteAtIndex(1); // 现在链表是1->3
linkedList.printLinkedList(); // 输出: 1 3
cout << linkedList.get(1) << endl; // 返回3
return 0;
}
反转链表
其中注释处是错误的,要是想加深以下理解,可以来我的直播间,大家一起学习!!!
#include<iostream>
using namespace std;
struct linknote
{
linknote* next;
int val;
linknote(int x):next(nullptr),val(x){}
};
//void fanzhuan(linknote*&start)
//{
// linknote* cur = start;
// linknote* temp = cur->next;
// while (temp!= nullptr)
// {
// temp->next = cur;
// cur = temp;
// temp = temp->next;
//
// }
// while (start != nullptr)
// {
// cout << start->val << " ";
// start = start->next;
// }
//} 这个代码虽然错了 但是你可以去找错 并改正 可以提高自己
void fanzhuan(linknote* start)
{
linknote* pre = nullptr;
linknote* cur = start;
linknote* temp;
while (cur!=nullptr)
{
temp = cur->next;//这个相当于是赋值
cur->next = pre;//这个相当于改变指针的指向
pre = cur;
cur = temp;
}
start = pre;//这个地方前方别忘了 相当于是反转了
while (start != nullptr)
{
cout << start->val << " ";
start = start->next;
}
}
int main()
{
linknote* p1 = new linknote(3);
linknote* p2 = new linknote(4);
linknote* p3 = new linknote(5);
linknote* p4 = new linknote(6);
p1->next = p2;
p2->next = p3;
p3->next = p4;
fanzhuan(p1);
}
小红书直播
为了能让大家更好的了解数据结构,大家可以关注我的小红书直播,欢迎大家一起进步,一起学习算法!我会在7.11号之后开课,希望能和大家一起讨论!!!