使用C++实现链表
struct ListNode{
int val;
ListNode* next;
ListNode(int x):val(x),next(nullptr){}
};
203.移除链表元素
题目描述:
两种解题思路:1、直接使用原链表进行操作。2、使用虚拟头节点(通用,且易于理解)。
第一种方法(操作原链表)
使用第一种方式的话需要区分删除的节点是不是头节点,因为是头节点的话只需要将头节点的指针重新赋值为指向头节点的下一个节点的指针。如下图所示:
若删除的不是头节点,则删除方式如下所示:
图中cur是临时定义的指针,因为需要对链表进行遍历,而最终需要返回head指针,所以需要保证head位于链表的头部不变。
第一种方法的代码实现
class Solution{
public:
ListNode* removeElements(ListNode* head, int val){
//判断是否是头节点
while(head != NULL && head->val = val){
ListNode* tmp = head;
head = head->next;
delete tmp;
}
//定义一个临时指针,用于遍历
ListNode* cur = head;
while(cur != NULL && cur->next != NULL){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else{
cur = cur->next;
}
}
return head;
}
};
第二种方法(虚拟头节点)
当使用虚拟头节点的时候需要重新new一个头节点,而这个虚拟头节点的下一个节点就是原始链表的头节点。下图是删除原链表头节点(红色)和非头节点(蓝色)的情况。cur指针同样是临时指针指向虚拟头节点(dy_head)。
虚拟头节点的代码实现
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode * dy_head = new ListNode(0);//new 一个虚拟头节点
dy_head->next = head; //虚拟头节点的下一个节点是head
ListNode* cur = dy_head;
while(cur->next != NULL){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else{
cur = cur->next;
}
}
head = dy_head->next;
delete dy_head;
return head;
}
};
707.设计链表
题目描述:
很基础的链表操作,将链表理解之后能够较为轻松的实现。
需要注意的是,新增节点的时候一定要先将新节点(newnode)的指针指向cur->next(红线),然后再将cur->next指向newnode(蓝线),因为如果第一步直接将cur->next指向newnode的话,newnode->next就不知指向何处了。
代码实现
lass MyLinkedList {
public:
struct ListNode{
int val;
ListNode* next;
ListNode(int x):val(x),next(nullptr){}
};
MyLinkedList() {
dy_head = new ListNode(0);
size = 0;
}
//获取第index节点的数值
int get(int index) {
if(index<0 || index> (size-1)){
return -1;
}
ListNode* cur = dy_head;
while(index){
cur = cur->next;
index--;
}
return cur->next->val;
}
//在头节点插入节点
void addAtHead(int val) {
ListNode* newnode = new ListNode(val);
newnode->next = dy_head->next;
dy_head->next = newnode;
size++;
}
//在尾节点插入节点
void addAtTail(int val) {
ListNode* newnode = new ListNode(val);
ListNode* cur = dy_head;
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newnode;
// newnode->next = NULL;
size++;
}
//在index处加入节点
void addAtIndex(int index, int val) {
if(index>size)return ;
if(index<0) index=0;
ListNode* newnode = new ListNode(val);
ListNode* cur = dy_head;
while(index){
cur = cur->next;
index--;
}
newnode->next = cur->next;
cur->next = newnode;
size++;
}
//删除指定节点
void deleteAtIndex(int index) {
if (index >= size || index < 0) {
return;
}
ListNode* cur = dy_head;
while(index){
cur = cur->next;
index--;
}
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
size--;
tmp = nullptr;
}
void printLinkelist(){
ListNode * cur = dy_head;
while(cur->next != nullptr){
cout<<cur->next->val<<" ";
cur = cur->next;
}
cout<<endl;
}
private:
int size;
ListNode* dy_head;
};
206.反转链表
题目描述:
解题思路:使用双指针法,定义一个pre指针和一个cur指针,初始化pre指针指向NULL,cur指针指向头节点head。然后通过让现在的节点指向上一个节点(cur->pre)一直到cur为NULL,则返回pre即将链表反转。
注意,使用双指针的时候,需要额外定义一个tmp指针用来指向cur的下个节点cur->next,因为如果直接使得cur->next =pre,则于后面的链表断开。然后更新pre和cur,注意,这里只能先更新pre,再更新cur,即pre = cur,cur=tmp。因为如果先cur=tmp的话,pre就无法完成更新。
代码实现
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = nullptr;
ListNode* tmp;
while(cur){
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
delete tmp;
tmp = nullptr;
return pre;
}
};