链表与数组不同,链表是映像存储,不像数组那样连续存址,所以对于链表删除节点应该按照下面的图示进行:
代码如下:
#include<iostream>
//#include<stdio.h>
#include<cmath>
#include<string>
using namespace std;
// // Definition for singly-linked list.
//struct 定义的是一个简单的单向链表节点,ListNode是一个链表节点,ListNode* 代表一个链表
//struct ListNode{
//int type;
//union {
// int i;
// string str;
//} val; // 联合体,用于保存不同类型的值
//ListNode *next;
//ListNode() : val{.i=0}, next(nullptr) {} //这是一个不带参数的构造函数,用冒号语法对val和next成员变量进行初始化。它将val初始化为0,next指针初始化为nullptr(空指针)。
//ListNode(string s) : val(), next(nullptr) {} //这是一个不带参数的构造函数,用冒号语法对val和next成员变量进行初始化。它将val初始化为0,next指针初始化为nullptr(空指针)。
//ListNode(int x) : val(x), next(nullptr) {} //在C++中,冒号可以用于成员初始化列表。构造函数是用于创建对象并对其进行初始化的特殊函数,使用冒号语法可以在构造函数内部设置成员变量的初始值。这种方式在效率和可读性上都比在构造函数体内赋值更好。
//ListNode(int x, ListNode* next) : val(x), next(next) {}
//ListNode(string s, ListNode *next) : str(s), next(next) {}
//};
// 在这个数据结构中,联合体中包含了两个不同类型的成员变量i和str。在构造函数ListNode(string s)中,使用了默认构造函数对联合体val进行初始化,但是此时联合体中没有指定具体的成员变量类型,编译器也无法知道应该使用哪个成员变量进行初始化。因此,在这里需要显式指定要初始化的成员变量。将构造函数ListNode(string s)中的val()修改为 { .str = s },即可指定要初始化联合体中的字符串变量str。这样修改后的代码如下:
struct ListNode {
int val;
//string str;
//union type{
// int i;
// string str;
//}; // 联合体,用于保存不同类型的值
ListNode* next;
ListNode() : val{ 0 }, next(nullptr) {} // 这是一个不带参数的构造函数,用冒号语法对val和next成员变量进行初始化。它将val初始化为0,next指针初始化为nullptr(空指针)。
// ListNode(string s) : type{ .str = s }, next(nullptr) {} // 这是一个不带参数的构造函数,用冒号语法对val和next成员变量进行初始化。它将val初始化为0,next指针初始化为nullptr(空指针)。
ListNode(int x): val{ x }, next(nullptr) {} // 在C++中,冒号可以用于成员初始化列表。构造函数是用于创建对象并对其进行初始化的特殊函数,使用冒号语法可以在构造函数内部设置成员变量的初始值。这种方式在效率和可读性上都比在构造函数体内赋值更好。
ListNode(int x, ListNode* next) : val{ x }, next(next) {}
// ListNode(string s, ListNode* next) : type{ .str = s }, next(next) {}
};
//删除对应值的节点
class Solution1 {
public:
//使用数组初始化量表
ListNode* createList(std::initializer_list<int> vals) {
ListNode dummy(0); //定义一个结构体变量dummy
ListNode* tail = &dummy; //将dummy的内存地址解引用
for (auto val : vals) {
tail->next = new ListNode(val); //将tail的指针所访问的内存,赋予值val,同时建立一个新的链表节点
tail = tail->next; //递归
}
return dummy.next;
}
ListNode* removeElements(ListNode* head, int targetval) {
//如果删除头结点
while(head->val == targetval && head != NULL) { //为啥不是if呢,如果删除头结点后发现,原来的第二个节点里的值也是targetval,如果用if就直接删除头结点后执行完了
ListNode* tempt = head;
head = head->next;
delete tempt;
}
//如果删除的是链表内部的节点
//ListNode* cur=ListNode*head;
ListNode* cur = head;
while (cur!= NULL && cur->next != NULL) {
if (cur->next->val != targetval) {
//ListNode* tempt = cur;
cur = cur->next;
// delete tempt;
}
else {
ListNode* tempt = cur->next;
cur->next = cur->next->next;
delete tempt;
}
}
return 0;
}
};
//定义输出链表单元操作
//void printList(ListNode* head) {
// ListNode* cur = head;
// while (cur != nullptr) {
// std::cout << cur->val << " ";
// cur = cur->next;
// }
//}
class UsingDummynode {
public:
ListNode* deletenode(ListNode* head, int val) {
// ListNode* freenode = (0);//会导致delete freenode越界,原因就是这是个静态指针,使用后会自动释放
ListNode* freenode=new ListNode(0); //delete freenode越界is OK
freenode->val = 0;
freenode->next = head;
//以上三段代码施加了一个虚拟节点
ListNode* cur = freenode;
while (cur!=NULL&&cur->next!=NULL){
if (cur->next->val == val) {
ListNode* tempt = cur;
cur->next = cur->next->next;
delete tempt;
}
else {
cur = cur->next;
}
}
// delete freenode;
return head;
}
};
//class designListNode {
//public:
// //获取第Index个链表的节点
//
// int Get_index_node(ListNode* head, int index) {
// ListNode* cur =head;
// int i = 0;
// // while (cur->val != NULL && i = index) {
// while (cur->val != NULL) {
// if (i+1 == index) {
// return cur->val; //如果当前节点编号==index,返回本节点的值
// break;
// }
// else if(i+1!=index){
// i=i+1;
// cur = cur->next; //如果当前节点的编号!=index,遍历i++
// }
// else {
// return -1;
// }
// }
// // while(cur->val != NULL&&i==index)
// }
// //在第Index个链表节点前插入新的节点
//
// ListNode* insert_before_index_node(ListNode* head, int index) {
// ListNode* cur = head;
// ListNode* waitting_insert_node=new ListNode();
// //waitting_insert_node->val = 6;
// int i = 0;
// // while (cur->val != NULL && i = index) {
// while (cur->val != NULL) {
// if (i == index) {//下一个节点就是待前插入节点
// ListNode* tempt = cur;
// waitting_insert_node->next = cur->next;
// cur->next = waitting_insert_node;
// delete tempt;
// break;
// }
// else if (i != index) {
// i = i + 1;
// cur = cur->next; //如果当前节点的编号!=index,遍历i++
// }
// else {
// return head;
// }
// }
// // while(cur->val != NULL&&i==index)
// delete waitting_insert_node;
// }
//};
int main()
{
Solution1 s1;
//UsingDummynode U1;
//designListNode designListNode1;
ListNode* testList = s1.createList({ 8, 2, 3, 4, 5, 6, 7 }); // 用{1,1,3,4,5,6,7}初始化链表
// ListNode* head = s1.createList({ 1, 2, 3, 4, 6, 6, 7 }); // 用{1,1,3,4,5,6,7}初始化链表
//ListNode* head =new ListNode (1, 2, 6, 3, 4, 5, 6); //C1001 内部编译器错误编译器无法为构造生成正确的代码,通常是由于特定表达式和优化选项的组合或分析中出现的问题。
ListNode* result = s1.removeElements(testList, 6);
//ListNode* result = U1.deletenode(testList, 1);
int index = 4;
// ListNode* result = designListNode1.insert_before_index_node(testList, index);
ListNode* check = result; //输出1 2 3 4 5 7
//ListNode* cur = &result; //"ListNode**类型的值不能用于初始化ListNode*类型的实体"其实原因就是,&result代表一个储存result指针的地址,而cur本身就是一个结构指针(指向ListNode类型的指针)
//ListNode* cur = result;
/*while (result != NULL) {
cout << result->val << " ";
result = result->next;
}*/
cout << "[";
while (check != NULL) {
cout << check->val; //check位置原来是cur,因为cur我用的动态存储,C++是不会自动清理内存的,所以如果我在main还使用cur,就会导致越界溢出
if (check->next != NULL)
{
cout << ",";
}
check = check->next;
} cout << "]";
//printList(result);
// cout << result;
return 0;
}