一、移除链表元素
法一:不使用虚拟头节点
ListNode* removeElements(ListNode* head, int val) {
//若删除头节点
while(head!=NULL&&head->val==val)//连续删除头节点的条件
{
head=head->next;
}
//删除其他节点(先判断是不是空链表)
if(head!=NULL){
ListNode* cur=head;
while(cur->next!=NULL){
if(cur->next->val==val)
{cur->next=cur->next->next;}
else
{cur=cur->next;}
}
}
return head;
}
法二:使用虚拟头节点
ListNode* dummy=new ListNode(0,head); //创建虚拟头节点并连接到原链表
ListNode* cur=dummy; //用来遍历的指针
while(cur->next!=NULL){
if(cur->next->val==val)
{cur->next=cur->next->next;}
else
{cur=cur->next;}
}
return dummy->next;
二、设计链表
单链表:
//先定义节点结构体
struct LinkNode{
int val;
LinkNode* next;
LinkNode(int val=0,LinkNode* next=NULL):val(val),next(next){}
};
class MyLinkedList {
int size; //链表的长度
LinkNode* dummy; //虚拟头节点
public:
MyLinkedList() {
//初始化链表:长度为0,初始化虚拟头节点
size=0;
dummy=new LinkNode();
}
// 析构函数,释放所有节点的内存
~MyLinkedList() {
LinkNode* cur = dummy;
while (cur != nullptr) {
LinkNode* temp = cur;
cur = cur->next;
delete temp; // 不断删除头节点,手动释放内存
}
}
int get(int index) {
//先判断index是否合理
if(index<0||index>size-1)
return -1;
else{
LinkNode* cur=dummy;
int loop=index+1;
while(loop--)
{
cur=cur->next;
}
return cur->val;
}
}
void addAtHead(int val) {
//先新建节点
LinkNode* newNode=new LinkNode(val);
//插入
newNode->next=dummy->next;
dummy->next=newNode;
size++;
}
void addAtTail(int val) {
LinkNode* newNode=new LinkNode(val);
LinkNode* cur=dummy;
while(cur->next!=NULL){
cur=cur->next;
}
cur->next=newNode;
size++;
}
void addAtIndex(int index, int val) {
//先判断index是否合理
if(index<0||index>size)
return;
LinkNode* newNode=new LinkNode(val);
LinkNode* cur=dummy;
int loop=index;
while(loop--)
{cur=cur->next;}
newNode->next=cur->next;
cur->next=newNode;
size++;
}
void deleteAtIndex(int index) {
//先判断index是否合理
if(index<0||index>size-1)
return;
int loop=index; //让cur指向下标为index-1的节点
LinkNode* cur=dummy;
while(loop--){
cur=cur->next;
}
cur->next=cur->next->next;
size--;
}
};
/**
* 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* reverseList(ListNode* head) {
//法一:逐个逆转方向
ListNode*cur=head,*pre=NULL,*temp;
while(cur)
{
temp=cur->next; //一存
cur->next=pre; //二改
pre=cur; //三移
cur=temp;
}
return pre;
}
递归写法:
//递归写法
ListNode* reverse(ListNode*cur,ListNode*pre){
if(cur==NULL) //终止条件
return pre;
ListNode* temp=cur->next; //先存
cur->next=pre; //后改向
return reverse(temp,cur); //进入下一轮逆转(将指针移动放进递归参数变化中)
}
ListNode* reverseList(ListNode* head) {
return reverse(head,NULL); //调用递归
}
法二:虚拟头节点+头插法
ListNode* reverseList(ListNode* head) {
//法二:虚拟头节点+头插法
ListNode*nummy=new ListNode();
ListNode*cur=head,*temp;
while(cur)
{
temp=cur->next; //一存
cur->next=nummy->next; //二头插
nummy->next=cur;
cur=temp; //三移
}
return nummy->next;
}
四、两两交换链表中的节点
法一:
ListNode* swapPairs(ListNode* head) {
//借用虚拟头节点,1+2的模式交换
ListNode*dummy=new ListNode(0,head);
ListNode*cur=dummy;
while(cur->next!=NULL&&cur->next->next!=NULL) //节点数为偶数或奇数时的循环条件(注意cur->next要写在前面,否则可能空指针异常)
{
//交换两个节点
ListNode *temp=cur->next;//先保存一个节点,防止丢失(也可以借助两个临时指针存储信息,不容易错乱)
cur->next=cur->next->next; //交换节点(三条线)
temp->next=cur->next->next;
cur->next->next=temp;
cur=cur->next->next; //指针移动
}
return dummy->next;
}
法二:递归法
五、删除链表的倒数第N个节点
法一:利用快慢指针
ListNode* removeNthFromEnd(ListNode* head, int n) {
//利用快慢指针的差值:n+1步;利用虚拟头指针,统一删除操作
ListNode *dummy=new ListNode(0,head);
ListNode*fast=dummy,*slow=dummy;
//快指针先走n+1步
for(int i=0;i<n+1;i++)
{
fast=fast->next;
}
//快慢指针再同时走,直至fast走到末尾
while(fast)
{
slow=slow->next;
fast=fast->next;
}
//删除节点
slow->next=slow->next->next;
return dummy->next;
}
法二:先计算出链表长度
int getLength(ListNode*head){
int length=0;
while(head){
length++;
head=head->next;
}
return length;
}
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode*dummy=new ListNode(0,head); //利用虚拟头节点,统一删除操作
ListNode*cur=dummy;
//先计算出链表长度
int lenght=getLength(head);
//再找要删除节点的前一个节点(转换成顺数第几个节点)最后一位:正序lenght,逆序1 所以逆序第n位,对应正序第lenght+1-n位
for(int i=0;i<lenght-n;i++) //cur走length-n步到达被删节点的前一个节点
{
cur=cur->next;
}
//最后删除节点
cur->next=cur->next->next;
return dummy->next;
}
六、环形链表
快慢指针:快指针速度为2,慢指针速度为1,若两个指针相遇则说明链表有环
(快指针比慢指针快即可,但是2:1是最高效的)
双指针:index1从头节点出发,index2从相遇节点出发,则两者的相遇点在入环节点
ListNode *detectCycle(ListNode *head) {
//若快慢指针相遇,则说明有环
ListNode*fast=head,*slow=head;
while(fast!=NULL&&fast->next!=NULL) //让快慢指针跑起来,结束条件是fast没到末尾(因为fast一下跳两步,所以还要保证fast->next不为空)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast) //若相遇,则说明有环
{
ListNode*index1=head,*index2=fast; //从出发点和相遇点各派出速度同为1的指针,则两者相遇点在入环节点
while(index1!=index2) //让两个指针跑起来,结束条件是index1==index2
{
index1=index1->next;
index2=index2->next;
}
return index1;
}
}
return NULL; //循环结束无环,返回null
}