• 链表


    链表

    一.实现链表的逆序

    给定一个带头结点的单链表,请将其逆序.即如果单链表原来为head->1->2->3->4->5->6->7,则逆序后变为head->7->6->5->4->3->2->1

    1.就地逆序

    主要思路为:在遍历链表的时候,修改当前结点的指针域的指向,让其指向它的前驱结点.为此需要用一个指针变量来保存前驱结点的地址.此外,为了在调整当前结点指针域的指向后还能找到后续结点,还需要另外一个指针变量来保存后续结点的地址,在所有的结点都被保存好以后就可以直接完成指针的逆序了.除此之外,还需要特别注意对链表首尾结点的特殊处理

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    # 方法功能:对单链表进行逆序
    # 输入参数:head 链表头结点
    def Reverse(head):
        if head==None or head.next==None:
            return
    
        pre=None # 前驱结点
        cur=None # 当前结点
        next=None # 后续结点
    
        # 把链表首结点变为尾结点
        cur=head.next
        next=cur.next
        cur.next=None
    
        pre=cur
        cur=next
        
        # 使当前遍历到的结点cur指向其前驱结点
        while cur.next!=None:
            next=cur.next
            cur.next=pre
            pre=cur
            cur=cur.next
            cur=next
        
        # 链表最后一个结点指向倒数第二个结点
        cur.next=pre
        # 链表的头结点指向原来链表的尾结点
        head.next=cur
    
    if __name__=="__main__":
        i=1
    
        head=LNode(i)
        head.next=None
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            tmp.next=None
            cur.next=tmp
            cur=tmp
            i+=1
    
        print("逆序前:")
    
        cur=head.next
    
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        print("
    逆序后:")
    
        Reverse(head)
        cur=head.next
    
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    逆序前:
    1 2 3 4 5 6 7 
    逆序后:
    7 6 5 4 3 2 1
    

    算法性能分析:这种方法只需要对链表进行一次遍历,因此时间复杂度为O(N),其中,N为链表的长度.但是需要常数个额外的变量来保存当前结点的前驱结点与后续结点,因此空间复杂度为O(1)

    2.递归法

    假定原链表为1->2->3->4->5->6->7,递归法的主要思路为:先逆序除第一个结点以外的子链表(将1->2->3->4->5->6->7变为1->7->6->5->4->3->2),依次类推

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    """
    方法功能:对不带头结点的单链表进行逆序
    输入参数:firstRef 链表头结点
            
    """
    def RecursiveReverse(head):
        if head is None or head.next is None:
            return head
        else:
            # 反转后面的结点
            newhead=RecursiveReverse(head.next)
            # 把当前遍历的结点加到后面结点逆序后链表的尾部
            head.next.next=head
            head.next=None
        return newhead
    
    
    """
    方法功能:对带头结点的单链表进行逆序
    输入参数:head 链表头结点
    """
    def Reverse(head):
        if head is None:
            return
    
        firstNode=head.next
        newhead=RecursiveReverse(firstNode)
    
        head.next=newhead
        return newhead
    
    if __name__=="__main__":
        i=1
    
        head=LNode(i)
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            tmp.next=None
            cur.next=tmp
            cur=tmp
            i+=1
    
        print("逆序前:")
    
        cur=head.next
    
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        print("
    逆序后:")
    
        Reverse(head)
        cur=head.next
    
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    逆序前:
    1 2 3 4 5 6 7 
    逆序后:
    7 6 5 4 3 2 1
    

    算法性能分析:时间复杂度为O(N).递归法的主要优点是:思路比较直观,容易理解,而且也不需要保存前驱结点的地址.缺点是:算法实现的难度较大

    3.插入法

    插入法的主要思路:从链表的第二个结点开始,把遍历到的节点插入到头结点的后面,直到遍历结束

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    
    
    def Reverse(head):
        if head is None or head.next is None:
            return
    
        cur=None # 当前结点
        next=None # 后续结点
    
        cur=head.next.next
        # 设置链表第一个结点为尾结点
        head.next.next=None
    
        # 把遍历到结点插入到头结点的后面
        while cur is not None:
            next=cur.next
            cur.next=head.next
            head.next=cur
            cur=next
    
    if __name__=="__main__":
        i=1
    
        head=LNode(i)
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            tmp.next=None
            cur.next=tmp
            cur=tmp
            i+=1
    
        print("逆序前:")
    
        cur=head.next
    
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        print("
    逆序后:")
    
        Reverse(head)
        cur=head.next
    
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    

    算法性能分析:时间复杂度为O(N)

    引申

    1. 对不带头结点的单链表进行逆序
    2. 从尾到头输出链表

    分析与解答

    1. 就地逆序+顺序输出
    2. 逆序+顺序输出
    3. 递归输出
    def ReversePrint(firstNode):
        if firstNode is None:
            return
        ReversePrint(firstNode.next)
        print(firstNode.data,end=" ")
    

    二.从无序链表中移除重复项

    1.顺序删除

    主要思路为:通过双重循环直接在链表上进行删除操作.外层循环用一个指针从第一个结点开始遍历整个链表,然后内层循环用另外一个指针遍历其余结点,将与外层循环遍历到的指针所指结点的数据域相同的结点删除

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    
    def removeDup(head):
        if head==None or head.next==None:
            return
    
        outerCur=head.next # 用于外层循环,指向链表第一个结点
        innerCur=None    # 用于内层循环用来遍历outercur后面的结点
        innerPre=None   # innerCur的前驱结点
    
        while outerCur!=None:
            innerCur=outerCur.next
            innerPre=outerCur
    
            while innerCur!=None:
                if outerCur.data==innerCur.data:
                    innerPre.next=innerCur.next
                    innerCur=innerCur.next
                else:
                    innerPre=innerCur
                    innerCur=innerCur.next
    
            outerCur=outerCur.next
    
    
    if __name__=="__main__":
        i=1
        head=LNode(i)
        head.next=None
    
        tmp=None
        cur=head
    
        while i<7:
            tmp=LNode(i)
            if i%2==0:
                tmp.data=i+1
            elif i%3==0:
                tmp.data=i-2
            else:
                tmp.data=i
    
            tmp.next=None
            cur.next=tmp
            cur=tmp
            i+=1
    
        print("删除重复结点前:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        removeDup(head)
        print("
    删除重复结点后:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    删除重复结点前:
    1 3 1 5 5 7 
    删除重复结点后:
    1 3 5 7
    

    **算法性能分析:**双重循环,其时间复杂度为O(N^2),空间复杂度为O(1)

    2.递归法

    主要思路为:对于结点cur,首先递归地删除以cur.next为首的子链表中重复的结点,接着从以cur.next为首的子链表中找出与cur有着相同数据域的结点并删除

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def removeDupRecursion(head):
        if head.next is None:
            return head
    
        pointer=None
        cur=head
    
        head.next=removeDupRecursion(head.next)
        pointer=head.next
    
        while pointer is not None:
            if head.data==pointer.data:
                cur.next=pointer.next
                pointer=cur.next
            else:
                pointer=pointer.next
                cur=cur.next
    
        return head
    
    
    
    def removeDup(head):
        if head is None:
            return
    
        head.next=removeDupRecursion(head.next)
    
    
    if __name__=="__main__":
        i=1
        head=LNode(i)
        head.next=None
    
        tmp=None
        cur=head
    
        while i<7:
            tmp=LNode(i)
            if i%2==0:
                tmp.data=i+1
            elif i%3==0:
                tmp.data=i-2
            else:
                tmp.data=i
    
            tmp.next=None
            cur.next=tmp
            cur=tmp
            i+=1
    
        print("删除重复结点前:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        removeDup(head)
        print("
    删除重复结点后:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    删除重复结点前:
    1 3 1 5 5 7 
    删除重复结点后:
    1 3 5 7
    

    算法性能分析:时间复杂度为O(N^2)

    3.空间换时间

    建立一个HashSet,HashSet中的内容为已经遍历过的结点内容,并将其初始化为空,从头开始遍历链表中的所有节点.如果结点内容已经在HashSet中,那么删除此结点,继续向后遍历,否则保留此结点,添加到HashSet,继续向后遍历

    三.计算两个单链表所代表的数之和

    1.整数相加法

    分别求两个链表所代表的整数的值,然后把这两个整数进行相加,最后把它们的和用链表的形式表示出来.优点:计算简单.缺点:当链表所代表的数很大的时候(超出了long的表示范围),就无法使用这种方法了

    2.链表相加法

    对链表结点进行相加操作,把相加的和存储到新的链表中对应的结点中,同时还要记录结点相加后的进位

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def add(h1,h2):
        if h1 is None or h1.next is None:
            return h2
    
        if h2 is None or h2.next is None:
            return h1
    
        c=0   # 用来记录进位
        sums=0 # 用来记录两个结点相加的值
        p1=h1.next  
        p2=h2.next
    
        tmp=None   # 用来指向新创建的存储相加和的结点
        resultHead=LNode(1)   # 相加后链表头结点
        p=resultHead  
    
        while p1 is not None and p2 is not None:
            sums=p1.data+p2.data+c
            tmp=LNode(sums%10)
            c=int(sums/10)
            p.next=tmp
            p=tmp
            p1=p1.next
            p2=p2.next
    
    
        if p1 is None:
            while p2 is not None:
                sums=p2.data+c
                tmp = LNode(sums%10)
                c=int(sums/10)
                p.next=tmp
                p=tmp
                p2=p2.next
    
        if p2 is None:
            while p1 is not None:
                sums=p1.data+c
                tmp = LNode(sums%10)
                c=int(sums/10)
                p.next=tmp
                p=tmp
                p1=p1.next
    
        if c==1:
            tmp=LNode(1)
            p.next=tmp
    
        return resultHead
    
    
    if __name__=="__main__":
        i=1
        head1=LNode(i)
        head2=LNode(i)
        tmp=None
        cur=head1
        addResult=None
    
        while i<7:
            tmp=LNode(i+2)
            cur.next=tmp
            cur=tmp
            i+=1
    
        cur=head2
    
        i=9
        while i>4:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i-=1
    
        print("Head1:")
    
        cur=head1.next
        while cur is not None:
            print(cur.data,end=" ")
            cur=cur.next
    
        print("
    Head2:")
        cur=head2.next
        while cur is not None:
            print(cur.data,end=" ")
            cur=cur.next
    
        addResult=add(head1,head2)
        print("
    相加后:")
    
        cur=addResult.next
        while cur is not None:
            print(cur.data,end=" ")
            cur=cur.next
    
    Head1:
    3 4 5 6 7 8 
    Head2:
    9 8 7 6 5 
    相加后:
    2 3 3 3 3 9
    

    四.对链表进行重新排序

    给定链表L0->L1->L2…Ln-1->Ln,把链表重新排序为L0->Ln->L1->Ln-1->L2->Ln-2….要求:(1)在原来链表的基础上进行排序,即不能申请新的结点;(2)只能修改结点的next域,不能修改数据域

    1.拆分

    主要思路:

    1. 首先找到链表的中间结点
    2. 对链表的后半部分子链表进行逆序
    3. 把链表的前半部分子链表与逆序后的后半部分子链表进行合并,合并的思路为:分别从两个链表各取一个结点进行合并
    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def FindMiddleNode(head):
        if head is None or head.next is None:
            return head
    
        fast=head  # 遍历链表的时候每次向前走两步
        slow=head  # 遍历链表的时候每次向前走一步
        slowPre=head
        
        # 当fast到链表尾时,slow恰好指向链表的中间结点
        while fast is not None and fast.next is not None:
            slowPre=slow
            slow=slow.next
            fast=fast.next.next
    
        # 把链表断开成两个独立的子链表
        slowPre.next=None
        return slow
    
    def Reverse(head):
        if head is None or head.next==None:
            return head
    
        pre=head
        cur=head.next
        next=cur.next
        pre.next=None
    
        while cur is not None:
            next=cur.next
            cur.next=pre
            pre=cur
            cur=cur.next
            cur=next
    
        return pre
    
    def Reorder(head):
        if head is None or head.next==None:
            return
    
        cur1=head.next
        mid=FindMiddleNode(head.next)
        cur2=Reverse(mid)
        tmp=None
    
        while cur1.next is not None:
            tmp=cur1.next
            cur1.next=cur2
            cur1=tmp
            tmp=cur2.next
            cur2.next=cur1
            cur2=tmp
    
        cur1.next=cur2
    
    if __name__=="__main__":
        i=1
        head=LNode(i)
        head.next=None
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=1
    
        print("排序前:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        Reorder(head)
        print("
    排序后:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    排序前:
    1 2 3 4 5 6 7 
    排序后:
    1 7 2 6 3 5 4
    

    算法性能分析:时间复杂度为O(N),空间复杂度为O(1)

    五.如何找出单链表中的倒数第k个元素

    1.顺序遍历两遍法

    首先遍历一遍单链表,求出整个单链表的长度n,然后求倒数第k个元素转换为求顺数第n-k个元素

    2.快慢指针法

    设置两个指针,让其中一个指针比另一个指针先前移k步,然后两个指针同时往前移动.循环直到先行的指针值为None时,另一个指针所指的位置就是所要找的位置

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def ConstructList():
        i=1
        head=LNode(1)
        head.next=None
    
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=1
        return head
    
    def PrintList(head):
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    def FindLastK(head,k):
        if head==None or head.next==None:
            return head
    
        slow=LNode(1)
        fast=LNode(1)
        slow=head.next
        fast=head.next
    
        i=0
        while i<k and fast!=None:
            fast=fast.next
            i+=1
    
        if i<k:
            return None
    
        while fast!=None:
            slow=slow.next
            fast=fast.next
        return slow
    
    
    if __name__=="__main__":
        head=ConstructList()
        result=None
        print("链表:")
        PrintList(head)
        result=FindLastK(head,3)
        if result!=None:
            print("
    链表倒数第3个元素为:",result.data)
    
    链表:
    1 2 3 4 5 6 7 
    链表倒数第3个元素为: 5
    

    算法性能分析:时间复杂度为O(N),空间复杂度为O(1)

    六.如何将单链表向右旋转k个位置

    主要思路:

    1. 首先找到链表倒数第k+1个结点slow和尾结点fast
    2. 把链表断开为两个子链表,其中后半部分子链表结点的个数为k
    3. 使原链表的尾结点指向链表的第一个结点
    4. 使链表的头结点指向原链表倒数第k个结点
    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    
    def RotateK(head,k):
        if head==None or head.next==None:
            return
    
        slow,fast,tmp=LNode(1),LNode(1),None
        slow,fast=head.next,head.next
        i=0
        while i<k and fast!=None:
            fast=fast.next
            i+=1
    
        if i<k:
            return
    
        while fast.next!=None:
            slow=slow.next
            fast=fast.next
    
        tmp=slow
        slow=slow.next
        tmp.next=None
        fast.next=head.next
        head.next=slow
    
    
    def ConstructList():
        i=1
        head=LNode(1)
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=1
        return head
    
    def PrintList(head):
        cur=head.next
    
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    
    if __name__=="__main__":
        head=ConstructList()
        print("旋转前:")
        PrintList(head)
        RotateK(head,3)
        print("
    旋转后:")
        PrintList(head)
    
    旋转前:
    1 2 3 4 5 6 7 
    旋转后:
    5 6 7 1 2 3 4
    

    算法性能分析:时间复杂度为O(N),空间复杂度为O(1)

    七.如何检测一个较大的单链表是否有环

    1.蛮力法

    定义一个HashSet用来存放结点的引用

    2.快慢指针遍历法

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    
    def ConstructList():
        i=1
        head=LNode(1)
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=1
    
        cur.next=head.next.next.next
        return head
    
    def isLoop(head):
        if head==None or head.next==None:
            return None
    
        slow=head.next
        fast=head.next
    
        while fast!=None and fast.next!=None:
            slow=slow.next
            fast=fast.next.next
    
            if slow==fast:
                return slow
        return None
    
    def findLoopNode(head,meetNode):
        first=head.next
        second=meetNode
    
        while first!=second:
            first=first.next
            second=second.next
    
        return first
    
    
    if __name__=="__main__":
        head=ConstructList()
        meetNode=isLoop(head)
        loopNode=None
    
        if meetNode!=None:
            print("有环")
            loopNode=findLoopNode(head,meetNode)
            print("环的入口点为:",loopNode.data)
        else:
            print("无环")
    
    有环
    环的入口点为: 3
    

    算法性能分析:时间复杂度为O(N),空间复杂度为O(1)

    八.如何把链表相邻元素翻转

    把链表相邻元素翻转,例如给定链表为1->2->3->4->5->6->7,则翻转后的链表变为2->1->4->3->6->5->7

    1.交换值法

    交换相邻两个结点的数据域

    2.就地逆序

    主要思路:通过调整结点指针域的指向来直接调换相邻的两个结点.如果单链表恰好有偶数个结点,那么只需要将奇偶结点对调即可,如果链表有奇数个结点,那么只需要将除最后一个节点外的其它结点进行奇偶对调即可

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    
    def reverse(head):
        if head==None or head.next==None:
            return
    
        cur=head.next # 当前遍历结点
        pre=head   # 当前结点的前驱结点
        next=None # 当前结点后续结点的后续结点
    
        while cur!=None and cur.next!=None:
            next=cur.next.next
            pre.next=cur.next
            cur.next.next=cur
            cur.next=next
            pre=cur
            cur=next
    
    def ConstructList():
        i=1
        head=LNode(1)
    
        tmp=None
        cur=head
    
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=1
        return head
    
    if __name__=="__main__":
        head=ConstructList()
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        reverse(head)
        print("
    逆序输出:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    1 2 3 4 5 6 7 
    逆序输出:
    2 1 4 3 6 5 7
    

    九.如何把链表以k个结点为一组进行翻转

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def ConstructList():
        i=1
        head=LNode(1)
    
        tmp=None
        cur=head
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=1
    
        return head
    
    def Reverse(head):
        if head==None or head.next==None:
            return head
    
        pre=head
        cur=head.next
        next=cur.next
        pre.next=None
    
        while cur!=None:
            next=cur.next
            cur.next=pre
            pre=cur
            cur=cur.next
            cur=next
        return pre
    
    def ReverseK(head,k):
        if head==None or head.next==None or k<2:
            return
    
        i=1
        pre=head
        begin=head.next
        end=None
        pNext=None
    
        while begin!=None:
            end=begin
    
            while i<k:
                if end.next!=None:
                    end=end.next
                else:
                    return
                i+=1
    
            pNext=end.next
            end.next=None
            pre.next=Reverse(begin)
            begin.next=pNext
            pre=begin
            begin=pNext
            i=1
    
    if __name__=="__main__":
        head=ConstructList()
        cur=head.next
        print("顺序输出:")
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
        ReverseK(head,3)
        print("
    逆序输出:")
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    顺序输出:
    1 2 3 4 5 6 7 
    逆序输出:
    3 2 1 6 5 4 7
    

    十.如何合并两个有序链表

    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def ConstructList(start):
        i=start
        head=LNode(1)
    
        tmp=None
        cur=head
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=2
    
        return head
    
    
    def PrintList(head):
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    def Merge(head1,head2):
        if head1==None or head1.next==None:
            return head2
        if head2==None or head2.next==None:
            return head1
    
        cur1=head1.next
        cur2=head2.next
    
        head=None
        cur=None
    
        if cur1.data>cur2.data:
            head=head2
            cur=cur2
            cur2=cur2.next
        else:
            head=head1
            cur=cur1
            cur1=cur1.next
    
        while cur1!=None and cur2!=None:
            if cur1.data<cur2.data:
                cur.next=cur1
                cur=cur1
                cur1=cur1.next
            else:
                cur.next=cur2
                cur=cur2
                cur2=cur2.next
    
        if cur1!=None:
            cur.next=cur1
        if cur2!=None:
            cur.next=cur2
    
        return head
    
    if __name__=="__main__":
        head1=ConstructList(1)
        head2=ConstructList(2)
        print("Head1:")
        PrintList(head1)
        print("
    Head2:")
        PrintList(head2)
        print("
    合并后的链表:")
        head=Merge(head1,head2)
        PrintList(head)
    
    Head1:
    1 3 5 7 
    Head2:
    2 4 6 
    合并后的链表:
    1 2 3 4 5 6 7
    

    算法性能分析:时间复杂度为O(N),空间复杂度为O(1)

    十一.如何在只给定单链表中某个结点的指针的情况下删除该结点

    分两种情况来分析:

    1. 如果这个结点是链表的最后一个结点,那么无法删除这个结点
    2. 如果这个结点不是链表的最后一个结点,可以通过把其后续结点的数据复制到当前结点中,然后删除后续结点的方法来实现
    class LNode(object):
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def ConstructList():
        i=1
        head=LNode(1)
    
        tmp=None
        cur=head
        p=None
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            if i==5:
                p=tmp
            i+=1
    
        return head,p
    
    
    def PrintList(head):
        cur=head.next
        while cur!=None:
            print(cur.data,end=" ")
            cur=cur.next
    
    def RemoveNode(p):
        if p==None or p.next==None:
            return False
        p.data=p.next.data
        tmp=p.next
        p.next=tmp.next
        return True
    
    if __name__=="__main__":
        head,p=ConstructList()
    
        print("删除结点"+str(p.data)+"前链表")
        PrintList(head)
        result=RemoveNode(p)
        if result:
            print("
    删除该结点后链表")
            PrintList(head)
    
    删除结点5前链表
    1 2 3 4 5 6 7 
    删除该结点后链表
    1 2 3 4 6 7
    

    十二.如何判断两个单链表(无环)是否交叉

    1.Hash法

    2.首尾相接法

    将两个链表首尾相连(例如把链表head1尾结点链接到head2的头指针),然后检测这个链表是否存在环,如果存在,则两个链表相交,二环入口结点即为相交的结点

    3.尾结点法

    如果两个链表相交,那么两个链表从相交点到链表结束都是相同的结点,必然是Y字形.即判断两个链表的最后一个结点是不是相同即可.分别遍历记下两个链表的长度n1,n2,在遍历一次,长链表结点先出发前进|n1-n2|步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点

    class LNode:
        def __init__(self,data):
            self.data=data
            self.next=None
    
    def IsIntersect(head1,head2):
        if head1==None or head1.next==None or head2==None or head2.next==None or head1==head2:
            return None
    
        temp1=head1.next
        temp2=head2.next
    
        n1,n2=0,0
    
        while temp1.next!=None:
            temp1=temp1.next
            n1+=1
    
        while temp2.next!=None:
            temp2=temp2.next
            n2+=1
    
        if temp1==temp2:
            if n1>n2:
                while n1-n2:
                    head1=head1.next
                    n1-=1
    
            if n1<n2:
                while n2-n1>0:
                    head2=head2.next
                    n2-=1
    
            while head1!=head2:
                head1=head1.next
                head2=head2.next
    
            return head1
        else:
            return None
    
    if __name__=="__main__":
        i=1
    
        head1=LNode(1)
        head2=LNode(1)
    
        tmp=None
        cur=head1
        p=None
    
        while i<8:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            if i==5:
                p=tmp
            i+=1
    
        cur=head2
        i=1
        while i<5:
            tmp=LNode(i)
            cur.next=tmp
            cur=tmp
            i+=1
    
        cur.next=p
    
        interNode=IsIntersect(head1,head2)
    
        if interNode==None:
            print("两个链表不相交")
        else:
            print("两个链表相交 "+str(interNode.data))
    
    两个链表相交 5
    

    算法性能分析:时间复杂度为O(n1+n2),空间复杂度为O(1)

    引申如果单链表有环,如何判断两个链表是否相交

    分析与解答

    1. 如果一个单链表有环,另外一个没环,那么它们肯定不相交
    2. 如果两个单链表都有环并且相交,那么这两个链表一定共享这个环.判断两个有环的链表是否相交的方法为:首先采用第7题介绍的找到链表head1中环的入口点p1,然后遍历链表head2,判断链表中是否包含结点p1,如果包含则相交,否则不相交;找相交点的方法为:把结点p1看作两个链表的尾结点,这样就可以把问题转换为求两个无环链表相交点的问题

    十三.展开链表列表

    from IPython.display import Image
    Image("./data/test2.png",width=500)
    

    output_84_0.png

    实现一个函数flatten(),该函数将链表扁平化成单个链表,扁平化的链表也应该被排序.输出链表为:3->6->8->11->15->21->22->30->31->39->40->45->50.主要思路使用归并排序中的合并排序,使用归并的方法用这些链表来逐个归并

    class LNode:
        def __init__(self,data):
            self.data=data
            self.right=None
            self.down=None
    
    
    class MergeList:
        def __init__(self):
            self.head=None
    
        # 用来合并两个有序的链表
        def merge(self,a,b):
            if a==None:
                return b
    
            if b==None:
                return a
            
            # 把两个链表头中较小的结点赋值给result
            if a.data<b.data:
                result=a
                result.down=self.merge(a.down,b)
            else:
                result=b
                result.down=self.merge(a,b.down)
    
            return result
    
        # 链表扁平化处理
        def flatten(self,root):
            if root==None or root.right==None:
                return root
    
            # 递归处理root.right链表
            root.right=self.flatten(root.right)
            # 把root结点对应的链表与右边的链表合并
            root=self.merge(root,root.right)
            return root
    
        # 将data插入链表头
        def insert(self,head_ref,data):
            new_node=LNode(data)
            new_node.down=head_ref
            head_ref=new_node
            # 返回新的表头结点
            return head_ref
    
        def printList(self):
            temp=self.head
            while temp!=None:
                print(temp.data,end=" ")
                temp=temp.down
    
    if __name__=="__main__":
        L=MergeList()
    
        L.head=L.insert(L.head,31)
        L.head=L.insert(L.head,8)
        L.head=L.insert(L.head,6)
        L.head=L.insert(L.head,3)
    
        L.head.right=L.insert(L.head.right,21)
        L.head.right=L.insert(L.head.right,11)
    
        L.head.right.right=L.insert(L.head.right.right,50)
        L.head.right.right=L.insert(L.head.right.right,22)
        L.head.right.right=L.insert(L.head.right.right,15)
    
        L.head.right.right.right=L.insert(L.head.right.right.right,55)
        L.head.right.right.right=L.insert(L.head.right.right.right,40)
        L.head.right.right.right=L.insert(L.head.right.right.right,39)
        L.head.right.right.right=L.insert(L.head.right.right.right,30)
    
        L.head=L.flatten(L.head)
        L.printList()
    
    3 6 8 11 15 21 22 30 31 39 40 50 55
    
  • 相关阅读:
    KDD 2018 | 最佳论文:首个面向Facebook、arXiv网络图类的对抗攻击研究
    Distill详述「可微图像参数化」:神经网络可视化和风格迁移利器!
    T1330 最少步数(#Ⅱ- 8)(广度优先搜索)
    细胞个数题解(广度优先搜索)
    DRL前沿之:Benchmarking Deep Reinforcement Learning for Continuous Control
    DRL 教程 | 如何保持运动小车上的旗杆屹立不倒?TensorFlow利用A3C算法训练智能体玩CartPole游戏
    强化学习是如何解决问题的?
    深度强化学习泡沫及路在何方?
    ECCV 2018 | UBC&腾讯AI Lab提出首个模块化GAN架构,搞定任意图像PS组合
    纵览神经架构搜索方法
  • 原文地址:https://www.cnblogs.com/LQ6H/p/12940550.html
Copyright © 2020-2023  润新知