leetcode 刷题 --单链表的经典题目

206.反转单链表

方法一:头插(最简单)

将原链表元素依次取下,进行头插

truct ListNode* reverseList(struct ListNode* head)
{
     struct ListNode*newhead=NULL;
     struct ListNode*cur=head;
    

    while(cur)
    {
        struct ListNode*next=cur->next;
        //头插
        cur->next=newhead;
        newhead=cur;
        cur=next;
        
    }
return newhead;
}

方法二 改变指针方向

定义三个指针

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseList(struct ListNode* head)
{
    //单独处理空链表
    if(head==NULL)
    return head;
    
     
    struct ListNode*n1,*n2,*n3;
    n1=NULL;
    n2=head;
    n3=n2->next;
    while(n2)
       {
        //反转指向
        n2->next=n1;
        //迭代
        n1=n2;
        n2=n3;

        if(n3)
             n3=n3->next;
       }
       return n1;
       
}

这个还可以用递归来做,但是链表过长时,程序容易崩溃。不建议用

201.移除链表元素

方法一:遍历+删除

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode*prev=NULL;
    struct ListNode*cur=head;

    while(cur)
    {
       
        if(cur->val==val)
        {
           if(cur==head)
            {
              //头删(要更新头节点)
              head=cur->next;
              free(cur);
              cur=head;
            }
           else
            {
             //删除
              prev->next=cur->next;
              free(cur);
              cur=prev->next;

             }
            
        }
        else 
        {
            prev=cur;
            cur=cur->next;
        }
    }
    return head;
}

方法二 遍历+尾插(用一个tail指针记下尾,方便多次尾插)

遍历,找到不等于val的值进行尾插

注意事项

1.结束时要处理尾节点

if(tail)  tail->next=NULL;

否则会出现下面的问题

leetcode 刷题 --单链表的经典题目_第1张图片

 2.开头head=NULL

否则

leetcode 刷题 --单链表的经典题目_第2张图片

 

 正确的完整代码

struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode*cur,*tail;
    cur=head;
    tail=NULL;
    head=NULL;
    while(cur)
    {
        if(cur->val==val)
        {
            //删除
            struct ListNode*del=cur;
            cur=cur->next;
            free(del);
        }
        else
        {
            //尾插
            if(tail==NULL)
            {
                head=tail=cur;
            }
            else
            {
                tail->next=cur;
                tail=tail->next;
            }
            cur=cur->next;
        }
    }
    if(tail)
    tail->next=NULL;
  return head;
}

方法三 :

方法三是在二的基础上添加了一个带哨兵位的头节点,可以规避掉注意实现1,2.

struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode*cur=head;
    struct ListNode*tail=NULL;
    
   //哨兵位的头节点
   head=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
   tail->next=NULL;
    while(cur)
    {
        if(cur->val==val)
        {
            //删除
            struct ListNode*del=cur;
            cur=cur->next;
            free(del);
        }
        else
        {
            //尾插
                tail->next=cur;
                tail=tail->next;
            
            cur=cur->next;
        }
    }

    tail->next=NULL;
//释放掉哨兵位头节点
 struct ListNode*del=head;
 head=head->next;
 free(del);

  return head;
}

876.链表的中间节点

                                ----快慢指针的简单应用


struct ListNode* middleNode(struct ListNode* head){
    assert(head);
    //快慢指针 
    //每次快指针比慢指针多走一步
struct ListNode*fast=head;
struct ListNode*slow=head;
while(fast!=NULL&& fast->next != NULL)
{
    fast=fast->next->next;
    slow=slow->next;
}
return slow;
}

你可能感兴趣的:(笔记,日常小记,链表,数据结构,算法,c语言)