数据结构-链表总结

  最近在学习链表,先做一下简单的总结:
一、链表的结构
二、链表常见的笔试题

  1. 合并两个排序好的链表
  2. 两个排序链表的交叉节点(后面详细介绍)
  3. 两个链表相加–最高位在头节点
  4. 两个链表相加–最高位在尾节点
  5. 判断链表是否为回文结构
  6. 待续………

一、链表的结构
  首先介绍一下链表的结构,链表是由节点组成。节点是一种数据类型(这样说对吗?)。节点分为两部分,数据部分和下一节点部分。下一节点部分存储的是当前节点的后面一个节点。
  代码实现:

class Node(object):
    def __init__(self, data):
        self.data = data
        self.next = None

注意:定义的self.next为None,而不是Node。

  一个数组或者一个链表生成一个链表,代码实现:

def LinkedList(pythonList):
    if len(pythonList) == 0:
        return None
    dummpy = Node(pythonList[0])
    p = dummpy
    for i in range(1, len(pythonList)):
        p.next = Node(pythonList[i])
        p = p.next
    return dummpy

上面pythonList就是一个列表或者一个数组。当这个列表的长度为0时,我们直接返回None。相当于这个链表为空。当链表长度不为0时,首先定义一个节点dummy,这个用于存储头节点,再定义一个p。p的作用是一个动态的指针,始终指向当前链表的最后一个节点,为什么呢?因为我们在存储节点时,只能把下一个节点存储在上一个节点的next里面。所以在for循环里面有那样两句话。存储p的下一个节点,p接着指向下一个节点,如此循环。请注意,最终返回的是dummy,因为它没有动,它始终指向头节点。所以我们只需要返回头节点,就可以获得整个链表。

二、题型解析

  1. 合并两个已经排序好的链表

Merge two sorted linked lists and return it as a new list. The new list should be madeby splicing together the nodes of the first two lists.
合并链表,也即是根据节点的数据大小来放入新的链表中,有两种情况:
第一是其中一个或两个为空,直接返回不为空的或任意一个均可以。
第二是都不为空,那就从头开始遍历两个链表,当然需要两个指针,比较这两个指针(l1, l2)所指的节点的数据大小,假设l1小,把小的放进去,我们能直接把另外一个大的l2放进去吗?当然不能,因为我们不知道l2和l1后面节点的大小关系啊。但是如果我们不放的话,加入刚才的l1是最后一个节点了,没有节点与l2比较了,那岂不是就要结束了,无缘无故丢掉一个节点。这时可以加一句判断,如果l1不为空,就把l1放进去,占个坑,然后再比较这个l1和刚才的那个l2的关系。

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        newLinkedList = ListNode(0)
        p = newLinkedList
# 其中一个为None,就返回另一个
        if None in (l1, l2):        
            return l1 or l2
# l1和l2是一个链表,而且指向链表的头部
# 这一段是比较两个节点的数值大小,小的就放入新的链表中,并分别指向下一个节点
        while l1 is not None and l2 is not None:  
            if l1.val < l2.val:                  
                p.next = l1
                l1 = l1.next
            else:
                p.next = l2
                l2 = l2.next

            p = p.next                            # p指向当前节点
# 这个地方的目的是为了将剩余的节点存进新的链表,比如说,上面l1.val和l2.val分别为最后一个节点,假如我们只存储了l1,还有l2没有存进来,此时l1已经是None,我们直接把l2存到最后就可以了,因为l1和l2的大小已经比过了。
            if l1 is not None:                    
                p.next = l1                        
            else:                                  
                p.next = l2                       
        return newLinkedList.next

上面的解释有点乱,看代码应该会比较清晰

  1. 两个链表的交叉节点

这个题目的意思是给定两个链表,找到一个节点,这个节点以及节点之后的数据在两个链表中是相同的。
这个问题比较的不仅仅是两个节点的数值相等,而且是两个节点的下一个节点也相等。所以说相等的节点的位置在两个链表中倒数是一致的,即这个节点在第一个链表中是倒数第二个,在另一个链表中也肯定是倒数第二个。如图所示:

所以当两个链表不一样长时,怎样比较?可以这样思考,两个指针,第一个指针遍历完第一个链表走五步,第二个指针遍历完第二个两个走六步。如果让第一个指针遍历完第一个链表之后指向第二个链表,第二个指针遍历完第二个链表之后指向第一个链表。当第二个指针指向第一个链表时,第二个指针是不是已经指向了第二个链表的第二个节点了(自己思考)。这样两个指针就同步了,就可以在对应位置进行比较了。当然有人会问,我们为什么不直接在短的链表的头所对应的长链表的位置开始比较(即a1,b2处)?那我们怎么才能获得链表的长度呢,不也是得遍历一次整个链表才能获得啊,这也是遍历了两次链表才完成的操作。

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        if headA is None or headB is None:
            return None

        pa = headA
        pb = headB

        while pa is not pb:
            if pa and pb:
                print(pa.data, pb.data)
            pa = headB if pa is None else pa.next
            pb = headA if pb is None else pb.next

        return pa

3.两个链表相加,最高位在头节点
这个题目的意思是给两个链表,每一个链表组成一个数,将这两个数相加,最后再将这个和转变成一个链表返回。

样例
给出 6->1->7 + 2->9->5。即,617 + 295。

返回 9->1->2。即,912

我的思路就是先将链表转换成数字,相加求和,再转变成链表,返回头节点即可。

class Node(object):
    def __init__(self, data):
        self.data = data
        self.next = None

def LinkedList(pythonList):
    if len(pythonList) == 0:
        return None
    dummpy = Node(pythonList[0])
    p = dummpy
    for i in range(1, len(pythonList)):
        p.next = Node(pythonList[i])
        p = p.next
    return dummpy

class Solution:
    """
    @param: l1: The first list.
    @param: l2: The second list.
    @return: the sum list of l1 and l2.
    """

    def addLists2(self, l1, l2):
        # write your code here
        a, b, c = 0, 0, 0
        while l1 is not None:
            a = a * 10 + l1.data
            l1 = l1.next
        while l2 is not None:
            b = b * 10 + l2.data
            l2 = l2.next

        c = a + b
        print(a, b, c)
        cList = str(c)
        print(cList)
        dummy = Node(int(cList[0]))
        p = dummy
        for i in range(1, len(cList)):
            p.next = Node(int(cList[i]))
            p = p.next

        return dummy

4.两个链表相加,最高位在头节点
这个和上一个思路是一样的,只是在处理数据方面略有不同

class Solution:
    # @param l1: the first list
    # @param l2: the second list
    # @return: the sum list of l1 and l2 
    def addLists(self, l1, l2):
        # write your code here
        head = ListNode(0)
        p = head
        a, b, c = 0, 0, 0
        i = 0
        while l1 is not None:
            a = a + l1.val * (10 ** i)
            l1 = l1.next
            i = i + 1

        i = 0
        while l2 is not None:
            b = b + l2.val * (10 ** i)
            l2 = l2.next
            i = i + 1
        c = a + b
        c = str(c)
        for num in c[::-1]:
            p.next = ListNode(int(num))
            p = p.next
        return head.next

5.判断链表是否为回文结构
回文结构就是第一个和最后一个的值相等第二个和倒数第二个,依次类推。思路就是,两个指针,一个快一个慢,快指针走两步,慢指针走一步,快指针走到最后,慢指针走到中间后面一个,同时将前面半个链表反转,这样就从中间开始向两边行走,对应位置相比较即可:

class Solution:
    """
    @param: head: A ListNode.
    @return: A boolean.
    """
    def isPalindrome(self, head):
        # write your code here
        slow = fast = head
        rev = None
        while fast and fast.next:
            fast = fast.next.next
            rev, rev.next, slow = slow, rev, slow.next
        if fast:
            slow = slow.next
        while rev and rev.val == slow.val:
            rev = rev.next
            slow = slow.next
        return not rev

猜你喜欢

转载自blog.csdn.net/qq_18293213/article/details/77923352