简体   繁体   English

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

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

I am trying to solve a linked list problem, to find the middle element in a single pass using python.我正在尝试解决一个链表问题,使用 python 在一次传递中找到中间元素。 Could someone please review my code and suggest the best manner to do this?有人可以查看我的代码并建议执行此操作的最佳方式吗?

  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)

I merged all the methods for you creating, finding and printing.我为您合并了所有创建、查找和打印的方法。

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)

Output:输出:

[ 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

Here's on way, it's one pass, though probably not as efficient as you'd like:这是在路上,它是一次通过,虽然可能没有你想要的那么高效:

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

does that work?那行得通吗?

You could keep two pointers, one that moves half as fast as the other.你可以保留两个指针,一个移动速度是另一个的一半。

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)

pseudo code for finding middle element of linked list : -用于查找链表中间元素的伪代码:-

fast = head
slow = head


while(fast!=null) {



 if(fast.next!=null) {

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

 else { 

  break
 }
}

// middle element
return slow

All of the above answers are right but for me, this worked best:以上所有答案都是正确的,但对我来说,这最有效:

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

Here, using floor helped me otherwise my code gave me errors.在这里,使用 floor 对我有帮助,否则我的代码会给我错误。

OK, this is NOT a good idea.好吧,这不是一个好主意。 But it DOES satisfy the constraint of traversing only once.但它确实满足只遍历一次的约束。 Instead of traversing once (and a secondary half traversal), it (ab)uses the stack to emulate the half traversal (backwards instead of forwards).它不是遍历一次(和二次半遍历),而是(ab)使用堆栈来模拟半遍历(向后而不是向前)。 It's not a good idea, because Python doesn't have an infinitely growable stack (I wish Python would take a cue from the Smalltalk guys on this one), so you really can only handle lists in the size of hundreds, definitely not thousands (this is Python3, btw).这不是一个好主意,因为 Python 没有无限增长的堆栈(我希望 Python 能从 Smalltalk 的家伙那里得到这个提示),所以你真的只能处理数百个大小的列表,绝对不能处理数千个(这是 Python3,顺便说一句)。

First I modified your script to build bigger lists with the change of a value:首先,我修改了您的脚本以通过更改值来构建更大的列表:

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

Since we're using the stack and recursion, we need a way to return abruptly out of a deep call stack.由于我们正在使用堆栈和递归,因此我们需要一种从深度调用堆栈中突然返回的方法。 So we create an Exception subclass, which is really more of a "notification" than an "exception".所以我们创建了一个 Exception 子类,它实际上更像是一个“通知”而不是“异常”。

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

Now for the recursive function:现在对于递归函数:

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

And to use it we do:为了使用它,我们这样做:

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

Not pretty.不漂亮。 Not a good idea in anything approximating production code.在任何近似生产代码的东西中都不是一个好主意。 But a decent example of (ab)using recursion and exceptions to fill the requirement of only traversing once.但是一个很好的例子(ab)使用递归和异常来满足只遍历一次的要求。

The best way to find the middle node is to have two pointers:找到中间节点的最好方法是有两个指针:

 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())

You can write a smaller code for finding the middle node.您可以编写更小的代码来查找中间节点。 Showing the snippet below:显示下面的片段:

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

Few important points:几个重要的点:

  1. Logic will remain the same of keeping two pointers, one fast and other slow.保持两个指针的逻辑将保持不变,一个快,另一个慢。
  2. Write a Linked list class to create a linked list with the help of loop rather than explicitly setting next pointers.编写一个链表类来在循环的帮助下创建一个链表,而不是显式设置下一个指针。

This is very similar to what James and Jordan have posted already, it's just little simpler in terms of what it does and I've added explanation as comments to what's actually doing这与詹姆斯和乔丹已经发布的内容非常相似,就它的作用而言,它只是简单一点,我已经添加了解释作为对实际操作的评论

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)

I might be little late but this works best for me.我可能会迟到,但这对我来说最有效。 Writing complete code for creating, finding the midpoint & printing the linked list.编写用于创建、查找中点和打印链表的完整代码。

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])

when i searched this question i was looking for something like this so i can get both middle values when entered even num of elements当我搜索这个问题时,我正在寻找这样的东西,所以我可以在输入偶数个元素时获得两个中间值

there must be a better way to do it i just start coding from like 3,4 day必须有更好的方法来做到这一点我只是从 3,4 天开始编码

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

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