链表

链表

一.实现链表的逆序

给定一个带头结点的单链表,请将其逆序.即如果单链表原来为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("\n逆序后:")

    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("\n逆序后:")

    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("\n逆序后:")

    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("\n删除重复结点后:")
    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("\n删除重复结点后:")
    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("\nHead2:")
    cur=head2.next
    while cur is not None:
        print(cur.data,end=" ")
        cur=cur.next

    addResult=add(head1,head2)
    print("\n相加后:")

    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("\n排序后:")
    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("\n链表倒数第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("\n旋转后:")
    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("\n逆序输出:")
    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("\n逆序输出:")
    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("\nHead2:")
    PrintList(head2)
    print("\n合并后的链表:")
    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("\n删除该结点后链表")
        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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值