【数据结构】——有关拼接、逆转的链表问题

上一篇文章我们讲了关于使用快慢指针来解决链表的相关问题,这篇文章我们就来主要讲一讲关于链表需要逆置的时候怎么做,有两个链表需要拼接的时候应该怎么做~

一、有关需要注意头结点的特殊问题

这类问题我们要注意新申请一个结点来保存头结点
1、删除链表中等于给定值val的所有结点
在这里插入图片描述
解题思路:
& 会出现给定结点为头结点的情况,所以应该重新定义一个结点用来保存头结点。
& 删除一个结点,应该找到这个结点的前一个结点,定义一个prve指针指向newnode结点
& 用if语句判定是否找到结点
& 最后用return返回删除后的结点

代码实现

ListNode* removeElements(ListNode* head, int val) {
      ListNode* newnode = new ListNode(val -1);
      newnode->next = head;
      ListNode* prev = newnode;
      while(prev->next != NULL)
      {
          if(prev->next->val == val)
          prev->next = prev->next->next;
          else 
          prev = prev->next;
      }
      return newnode->next;
    }

2、删除重复结点——注意重复结点就为头结点的情况
在这里插入图片描述
解题思路:
& 先判断链表为空的特殊情况
& 与之前的删除一个结点题类似,要添加一个头结点,以便碰到第一个第二个结点就相同的情况
& 设置prev,last指针,prev指针指向当前确定不重复的那个结点,而last指针相当于工作指针,一直往后搜索
& 注意,最后两个结点相同的特殊情况

代码求解:

ListNode*
deleteDuplication(ListNode* pHead)
    {
        if(pHead == NULL || pHead->next ==NULL)
            return pHead;
        ListNode* newnode = new ListNode(-1);
        newnode->next = pHead;
        ListNode* prev = newnode;

ListNode* last = newnode->next;
    while(last != NULL)
    {
    if(last->next != NULL &&
last->val == last->next->val)
    {
        //找到最后一个相同结点的情况
        while(last->next != NULL &&
last->val == last->next->val)
        {
           last = last->next;
        }
        prev->next = last->next;
        last = last->next;
    }
    else
    {
        prev= prev->next;
        last = last->next;
    }
    }
    return newnode->next;
}

二、关于反转链表要改变指针指向的问题

此类问题的关键是整个反转过程代码为:

ListNode* temp = cur->next;
           cur->next = prev;
           prev = cur;
           cur = temp;

1、反转一个单链表在这里插入图片描述
解题思路:
& 反转链表实质上就是改变箭头指向,首先定义一个prev结点为NULL
& 再定义一个cur结点为head结点,后面用于遍历链表
& 在定义一个temp结点用于保存原链表cur下一个结点
& 把cur结点的指针指向prev,再更新cur结点,最后cur结点再遍历下一个结点
& 以此往复

代码实现:

ListNode* reverseList(ListNode* head) {
       ListNode* prev = NULL;
       ListNode* cur = head;
       while(cur != NULL)
       {
           ListNode* temp = cur->next;
           cur->next = prev;
           prev = cur;
           cur = temp;
       }
       return prev;
}

2、判断一个链表是否为回文结构
在这里插入图片描述
解题思路:
& 利用快慢指针,第一步设置一个快指针和慢指针
& 快指针一次走两步,慢指针一次走一步,当快指针下一步为null的时候说明慢指针已经走了一半,这样就可以找到中间结点
& 再反转中间链表后面的指针
& 再从头到尾向中间扫描,对比每个元素是否相等,如果都相等就是回文数,否则不是回文数

代码求解:



bool
chkPalindrome(ListNode* A) {
        if(A == NULL)
        return false;
    else if(A->next == NULL)
        return true;
    //快慢指针找出中间结点
    ListNode* fast = A;
    ListNode* slow = A;
    while(fast != NULL && fast->next
!= NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    //反转
    ListNode* p = slow->next;
    ListNode* p1 = p->next;
    while(p != NULL)
    {
        p->next = slow;
        slow = p;
        p = p1;
        p1 = p1->next;
    }
    //比较
    while(A != slow)
    {
        if((A->val) != (slow->val))
        {
           return false;
        }
        else 
        {
           if(A->next == slow)
           {
               return true;
           }
           A = A->next;
           slow = slow->next;
        }
    }
    return true;
}

三、有关链表拼接的问题

这种问题的关键就是找准哪个链表拼接在哪个链表后面
1、将两个有序链表合并成一个新的有序链表
在这里插入图片描述
解题思路:
& 特殊情况判断,当两个链表其中一个为空时
& 采用递归的方式完成

代码求解:

 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == NULL)
        return l2;
        else if(l2 == NULL)
        return l1;
        else if(l1->val < l2->val
        {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else 
        {
           l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
}

2、链表分割
在这里插入图片描述
问题分析:
& 特殊情况判断,当链表为空的时候
& 设置两个链表头,smalllist追加小数链表,biglist追加大数链表。遍历原链表
& 最后将小数链表沾到大数链表前边即为结果

代码求解:

ListNode*
partition(ListNode* pHead, int x) {
        if(pHead == NULL)
        return NULL;
    ListNode* smallList = new ListNode(-1);
    ListNode* bigList = new ListNode(-1);
    ListNode* ps = smallList,*pb = bigList,*cur= pHead;
    while(cur)
    {
        if(cur->val < x)
        {
           ps->next = cur;
           ps = cur;
//先让尾节点的next指向cur,然后再将尾节点指针指向cur,相当于在链表尾部添加了一个节点。
        }
        else
        {
           pb->next = cur;
           pb = cur;
        }
        cur = cur->next;
    }
    pb->next = NULL;
    ps->next = bigList->next;
    return smallList->next;
    }

2、编写一个程序,找到两个单链表相交的起始结点
在这里插入图片描述
问题分析:
& 采用双指针的方式:依次遍历链表A和链表B,谁先遍历完就到另外一个链表的头部开始继续遍历。最后如果两个链表存在相交,他们末尾的结点必然相同,记录下链表对应的元素。若最后元素不相同,则两个链表不相交。

代码求解:

 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if( !headA || !headB)
        return NULL;
    ListNode* headA_bak = headA;
    ListNode* headB_bak = headB;
    while( headA != headB)
    {
        if( headA == NULL)
        { headA = headB_bak;}
        else
        { headA = headA->next;}
        if( headB == NULL)
        { headB = headA_bak;}
        else
        { headB = headB->next;}
    }
    return headA;    
发布了62 篇原创文章 · 获赞 7 · 访问量 2584

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104316085
今日推荐