繁体   English   中英

如何在python中一次性找到链表的中间元素?

[英]How to find middle element of linked list in one pass in python?

我正在尝试解决一个链表问题,使用 python 在一次传递中找到中间元素。 有人可以查看我的代码并建议执行此操作的最佳方式吗?

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

  def print_nodes(node):
      while node:
          print node
          node = node.next

  def find_middle(node):
      while node:
          current = node
          node = node.next
          second_pointer = node.next
          next_pointer = second_pointer.next
          if next_pointer is None:
              return "Middle node is %s" % str(current)

  node1 = Node(1)
  node2 = Node(2)
  node3 = Node(3)
  node4 = Node(4)
  node5 = Node(5)

  node1.next = node2
  node2.next = node3
  node3.next = node4
  node4.next = node5

  print find_middle(node1)

我为您合并了所有创建、查找和打印的方法。

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

def create_linked_list(n):
    """Creating linked list for the given
       size"""
    linked_list = Node(1)
    head = linked_list
    for i in range(2, n):
        head.next = Node(i)
        head = head.next
    return linked_list

def print_linked_list(node):
    """To print the linked list in forward"""
    while node:
        print '[',node,']','[ref] ->',
        node = node.next
    print '-> None'

def find_middle1(node):
    tick = False
    half = node
    while node:
        node = node.next
        if tick:
            half = half.next
        tick = not tick
    return "Middle node is %s" % str(half)

def find_middle2(node):
    list = []
    while node:
        list.append(node)
        node = node.next
    return "Middle node is %s" % str(list[len(list)/2])


node = create_linked_list(10)
print_linked_list(node)

print find_middle1(node)
print find_middle2(node)

输出:

[ 1 ] [ref] -> [ 2 ] [ref] -> [ 3 ] [ref] -> [ 4 ] [ref] -> [ 5 ] [ref] -> [ 6 ] [ref] -> [ 7 ] [ref] -> [ 8 ] [ref] -> [ 9 ] [ref] -> -> None
Middle node is 5
Middle node is 5

这是在路上,它是一次通过,虽然可能没有你想要的那么高效:

def find_middle(node):
    list = []
    while node:
        list.append(node)
        node = node.next
    return list[len(list)/2]

那行得通吗?

你可以保留两个指针,一个移动速度是另一个的一半。

def find_middle(node):
    tick = False
    half = node
    while node:
        node = node.next
        if (tick):
            half = half.next
        tick = not tick
    return "Middle node is %s" % str(half)

用于查找链表中间元素的伪代码:-

fast = head
slow = head


while(fast!=null) {



 if(fast.next!=null) {

      fast = fast.next.next
      slow = slow.next
 }

 else { 

  break
 }
}

// middle element
return slow

以上所有答案都是正确的,但对我来说,这最有效:

        def middleNode(self, head: ListNode) -> ListNode:
            list=[]
            while head:
                list.append(head)
                head=head.next
            return list[floor(len(list)/2)]

在这里,使用 floor 对我有帮助,否则我的代码会给我错误。

好吧,这不是一个好主意。 但它确实满足只遍历一次的约束。 它不是遍历一次(和二次半遍历),而是(ab)使用堆栈来模拟半遍历(向后而不是向前)。 这不是一个好主意,因为 Python 没有无限增长的堆栈(我希望 Python 能从 Smalltalk 的家伙那里得到这个提示),所以你真的只能处理数百个大小的列表,绝对不能处理数千个(这是 Python3,顺便说一句)。

首先,我修改了您的脚本以通过更改值来构建更大的列表:

last = root = Node(1)
for i in range(2, 312):
    node = Node(i)
    last.next = node
    last = node

由于我们正在使用堆栈和递归,因此我们需要一种从深度调用堆栈中突然返回的方法。 所以我们创建了一个 Exception 子类,它实际上更像是一个“通知”而不是“异常”。

class FoundMiddleNode(Exception):
    def __init__(self, node):
        super().__init__()
        self.node = node

现在对于递归函数:

def probeForMiddle(node, length):
    if node.next is None: #recursion stopper
        return length
    #call recursively
    lengthToEnd = probeForMiddle(node.next, length + 1)
    #is my distance from start half of what is being returned recursively as the full length?
    if (lengthToEnd // 2) - length == 0: 
        raise FoundMiddleNode(node) #throw an exception to abort the rest of the stack walk
    return lengthToEnd

为了使用它,我们这样做:

try:
    probeForMiddle(root, 0)
except FoundMiddleNode as e:
    print(e.node)

不漂亮。 在任何近似生产代码的东西中都不是一个好主意。 但是一个很好的例子(ab)使用递归和异常来满足只遍历一次的要求。

找到中间节点的最好方法是有两个指针:

 P1 = root
    P2 = root
    While not p2.next == Null:
    P1 =p1.next
    P2 =P2.next.next
//Linked list

ll = {'A': ["data", "B"],
 'B': ["data", "C"],
 'C': ["data", "D"],
 'D': ["data", "E"],
 'E': ["data", None]}


def find_next_node(node="A"):
    return ll[node][1] if ll[node][1] else None

def find_mid_node(head="A"):
    slow = head
    fast = head
    while(fast!=None):
        for i in range(2):
            if find_next_node(fast):
                fast = find_next_node(node=fast)
            else:
                return slow

        for j in range(1):
            slow = find_next_node(node=slow)


print (find_mid_node())

您可以编写更小的代码来查找中间节点。 显示下面的片段:

   def find_middle(node):
      half = node
      while node and node.next is not None:
         node = node.next.next
         half = half.next
      return half

几个重要的点:

  1. 保持两个指针的逻辑将保持不变,一个快,另一个慢。
  2. 编写一个链表类来在循环的帮助下创建一个链表,而不是显式设置下一个指针。

这与詹姆斯和乔丹已经发布的内容非常相似,就它的作用而言,它只是简单一点,我已经添加了解释作为对实际操作的评论

class Node:
  def __init__(self, data=None, next=None):
    self.data = data
    self.next = next 
# loop through the items and check for next items using two pointers (fast and slow)
# set the speed for fast twice higher than the slow pointer so when when fast reaches
# the end the slow would be in the middle
def find_middle(head ):
    fast = slow = head 
    #slow = head
    while fast.next != None and fast.next.next != None:
        fast = fast.next.next
        slow = slow.next

    # slow is now at the middle :)
    print (slow.data  )


#setup data
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)

node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5

find_middle(node1)

我可能会迟到,但这对我来说最有效。 编写用于创建、查找中点和打印链表的完整代码。

class Node:
    '''
    Class to create Node and next part of the linked list
    '''
    def __init__(self,data):
        self.data = data
        self.next = None
        

def createLL(arr):
    '''
    linked list creation
    '''
    head = Node(arr[0])
    tail = head
    for data in arr[1:]:
        tail.next = Node(data)
        tail = tail.next
        
    return head

def midPointOfLL(head):
    '''
    Here, i am using two pointers slow and fast, So idea is fast will be 2 times faster than slow pointer
    and when fast reaches the end of the linked list slow pointer will be exactly in the middle.
    '''

    slow = head
    fast = head
    if head is not None:
        while (fast.next is not None) and (fast.next.next is not None):
            slow = slow.next
            fast = fast.next.next
        
    return slow

def printLL(head):
    curr = head
    while curr :
        print(curr.data,end = "-->")
        curr = curr.next
    print('None')


arr  = list(map(int,input().split())) 
head = createLL(arr)       
midPoint = midPointOfLL(head)
print(midPoint.data)
printLL(head)
list=['ok','go','no','poi','duo','ok','go','nah']
b=0
b=int(len(list)/2) #print the middle element change .5 values 
print(list[b])
if((len(list)%2)==0): #if list is of even number print both middle values
    print(list[b+1])

当我搜索这个问题时,我正在寻找这样的东西,所以我可以在输入偶数个元素时获得两个中间值

必须有更好的方法来做到这一点我只是从 3,4 天开始编码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM