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

时间:2013-12-02 03:42:53

标签: python algorithm list data-structures linked-list

我正在尝试解决链表问题,使用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)

12 个答案:

答案 0 :(得分:4)

现在正在进行中,这是一次通过,但可能没有您想要的那么高效:

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

有效吗?

答案 1 :(得分:4)

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

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

答案 2 :(得分:3)

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

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)

答案 3 :(得分:2)

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

fast = head
slow = head


while(fast!=null) {



 if(fast.next!=null) {

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

 else { 

  break
 }
}

// middle element
return slow

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:0)

好的,这不是个好主意。但它只满足遍历一次的约束。它(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)使用递归和异常来填充仅遍历一次的要求的一个很好的例子。

答案 6 :(得分:0)

String pattern = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
    .withLocale(locale).format(LocalTime.MIN)
    .replaceFirst("\\d*", "H").replaceFirst("\\d.*", "mm");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, locale);
int minutes = formatter.parse(string).get(ChronoField.MINUTE_OF_DAY);

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

必须有一个更好的方法来实现它我只需从3,4天开始编码

答案 7 :(得分:0)

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

                   samples  subject  trial_num
0    '[string1, string21, string3]'        1          1
1    '[string3, string24, string3]'        1          2
2    '[string4, string24, string4]'        1          3
3    '[string5, string24, string5]'        2          1
4    '[string13, string24, string6]'        2          2
5    '[string16, string24, string6]'        2          3

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

wordarray

一些要点:

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

答案 10 :(得分:0)

这与James和Jordan所发布的内容非常相似,只是在功能上稍简单一些,我在实际操作中添加了解释作为注释

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)

答案 11 :(得分:0)

我可能迟到了,但这对我来说效果最好。编写完整的代码以创建,找到中点并打印链接列表。

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)