今天刚上来有点疲惫 但是由于是二刷 还是轻松不少
链表:
一个结点是由数据域和指针域组成的 其中指针域存放指项下一个结点的指针 最后的结点指向nuLL
u主要就是c++中链表结点是如何定义的 因为leetcode中都定义好了 所以很多人写不出来
其实就是
struct listnode{
int val;
listnode *next;
listnode(int x): val(x), next(NULL) {} //这个构造函数其实是构造一个头结点 所以只用传val就行了 next是指向NULL的(next的默认值为null)
}
这个最后可加分号可不加.
第一题:移除链表元素
还是要注意几个点
1 就是你定义了struct类的结构体后 不能再用int *p去指向它 因为它已经是listnode 型的指针了 只能说是定义一个listnode *p 类型的指针 去指向。 此外也没有必要去调用构造函数 去创建一个p 因为只能说创建一个指针 而不是创建对象。
2第二个问题是 你如果是定义了指针去指向 那么你就不能用. 而是要用-> 因为.是结构体的东西 而->是相当于是委托 而且是委托到底 去最终去得到这个值
3free是c语言用的 c++用的是delete 而且要注意不管是free还是delete后 这个指针p就无效了 要重新定义。 所以要在循环里定义一个tem变量用于释放。在c++中 `delete`不会只释放指针本身,而是会同时释放指针所指向的对象。
4第四个问题就是 你可以虚拟一个头结点 但是最后一定要注意回收 不然就出问题了。
最终代码如下:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *head1 =new ListNode ();
head1->next=head;
ListNode *p=head,*pre=head1;
while(p!=NULL){
if(p->val==val){
ListNode *tem=p;
pre->next=p->next;
p=p->next;
delete tem;
}
else{
p=p->next;
pre=pre->next;
}
}
head=head1->next;
delete head1;
return head;
}
};
第二题
1注意初始化 指得是让你生成头结点 而不是让你定义结构
2注意在初始化的时候 最好要加一个size值 这样方便操作。 在单向链表和双向链表中 都最好去加上一个size值。 这个size就是链表下表 可以看看题目的要求来决定
3另外就是在初始化的时候 只用初始虚拟头结点就可以了 不用定义头结点 因为头结点也就是第一个数据 在插入的时候直接插入就可以了
4还是要注意: 从0开始! 数组下标从0开始!
5 LinkedNode *p p是定义在栈上的 只有new出来的才是定义在堆上的。
6在创建链表的时候,最好是直接创建成引用或者指针类型 而不是直接定义一个对象 因为这样会速度很快
你就想嘛 你直接操作很多对象 哪有直接操作指向对象的指针快呢
具体原因:在链表的实现中,由于需要频繁对节点进行插入、删除等操作,因此使用指针会比使用对象更加方便,这是因为在使用指针时可以直接通过内存地址进行操作,而在使用对象时需要进行额外的拷贝或者构造,会产生额外的开销。
因此,在链表的实现中,通常会使用节点的指针来表示链表,这样可以方便地进行插入、删除、查找等操作。在具体实现中,可以在节点类中使用智能指针,如shared_ptr
或unique_ptr
,来管理节点的内存,以避免手动管理指针所带来的安全问题。
7还有就是
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};
这个构造函数的
LinkedNode(int val):val(val), next(nullptr){}
这一行 不用在next前加指针 因为next本身就是指针变量 只是在定义的时候前面要加*
8 如果你是用多一个size 那么你要时时刻刻去维护这个size
9如果是有节点下标的题 那么就肯定要用一个size
10就是可以说用一个size去维护 也可以说是用循环编历 相当于说是循环 看是否相等
11要注意size要先定义为int
12c++中写完public 还要写private
13还有要注意在函数中定义的变量 只能在函数的作用域中使用。 不然就必须在private里面再去定义。 这样在整个类中都能使用。 再去使用的时候,不用去再去声明类型 只要用名称就可以了。
另外最好用_下划线 这个成员访问符来访问:成员访问符 " _ "(下划线)在C++中常用于区分成员变量和局部变量或函数参数。因为C++允许在函数内部定义局部变量或参数的名称与成员变量的名称相同,如果没有使用成员访问符来区分,编译器可能会将局部变量或参数当成成员变量使用,导致程序出现错误。
class MyLinkedList { public: struct LinkedNode { int val; LinkedNode* next; LinkedNode(int val):val(val), next(nullptr){} }; MyLinkedList() { head = new LinkedNode (0); size1 = 0; } int get(int index) { if(index >=size1||index<0){ return -1; } LinkedNode* p=head->next; while(index--){ p=p->next; } return p->val; } void addAtHead(int val) { LinkedNode *pre=new LinkedNode (val); LinkedNode *p=head->next; head->next=pre; pre->next=p; size1++; } void addAtTail(int val) { LinkedNode *p=head; LinkedNode *newnode=new LinkedNode (val); while(p->next!=NULL){ p=p->next; } p->next=newnode; newnode->next=NULL; size1++; } void addAtIndex(int index, int val) { if(index>size1||index<0) {return;} if(index==size1){ addAtTail(val); return; } LinkedNode *p=head; while(index--){ p=p->next; } LinkedNode *newcode=new LinkedNode (val); newcode->next=p->next; p->next=newcode; size1++; } void deleteAtIndex(int index) { if(index >=size1||index<0){ return ; } LinkedNode *p=head; while(index--) p=p->next; LinkedNode *tem=p->next; p->next=p->next->next; delete tem; size1--; } private: int size1; LinkedNode* head; }; /** * 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主要是你在反转链表的时候 应该是用p->next去指向pre->next 注意!!
2还有一个点是 也可以直接把指向NULL的指针再去回指 不会出问题 指向NULL也是指针
3还有一个问题是 反转链表其实不用prehead结点 就算你加上 到最后如果链表是NULL的话,那么你去返回的时候就有问题了 不是返回的pre。 所以这样还要单独讨论 所以最好就是不去加头结点 因为你是反转链表 加了反而有问题 不如直接把pre设为NULL就是最好。 这点需要去学习一下 因为直接不管是插入还是什么的 都是在之后去弄 而不是之前去弄 你设计虚拟头结点如果是之前去弄的话就反而更麻烦了。
具体代码如下 还是很简单的 就是一些细节要注意:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* p=head;
ListNode* pre=NULL;
while(p!=NULL){
ListNode* tem=p->next;
p->next=pre;
pre=p;
p=tem;
}
return pre;
}
};
因为第二题掌握的不好所以再去重做一下:
1 如果题目没有去struct定义 那么你就要自己定义了 在函数之前。
2注意struct要用分号结尾! 因为c++中struct和类一样都要用分号结尾