如何在不遍历整个列表的情况下查找链接列表中的中间元素?

时间:2013-05-08 17:06:08

标签: data-structures

如何在不遍历整个列表的情况下在链接列表中查找中间元素。 ? ...并且最多只能使用2个指针......怎么办? ....还没有给出列表的长度。

14 个答案:

答案 0 :(得分:27)

除非你知道长度,否则我没有看到如何在不遍历整个列表的情况下完成它。

我猜测答案是希望一个指针一次遍历一个元素,而第二个指针一次移动2个元素。
这样,当第二个指针到达结尾时,第一个指针将位于中间。

答案 1 :(得分:11)

以下代码将帮助您获得中间元素。 你需要使用两个指针“快”和“慢”。在每一步,快速指针将增加2,慢速将增加1。当列表结束时,慢速指针将位于中间。

让我们考虑Node看起来像这样

class Node
{
  int data;
  Node next;
}

LinkedList有一个getter方法来提供链表的头部

public Node getHead()
{
  return this.head;
}

以下方法将获取列表的中间元素(不知道列表的大小)

public int getMiddleElement(LinkedList l)
{
    return getMiddleElement(l.getHead());
}

private int getMiddleElement(Node n)
{
    Node slow = n;
    Node fast = n;

    while(fast!=null && fast.next!=null)
    {
        fast = fast.next.next;
        slow = slow.next;
    }

    return slow.data;
}

示例:
如果列表是1-2-3-4-5,则中间元素是3
如果列表是1-2-3-4,则中间元素是3

答案 2 :(得分:1)

在C中,使用指针,以获得完整性。请注意,这是基于用于检查链表是否包含循环的“Tortoise and Hare”算法。

我们的节点定义如下:

typedef struct node {
    int          val;
    struct node *next;
} node_t;

然后我们的算法就是:

node_t *
list_middle (node_t *root)
{
    node_t *tort = root;
    node_t *hare = root;

    while (hare != NULL && hare->next != NULL) {
        tort = tort->next;
        hare = hare->next->next;
    }

    return (tort);
}

对于具有偶数个节点的列表,这将返回处理实际中心的节点(例如,在10个节点的列表中,这将返回节点6)。

答案 3 :(得分:0)

有两个可能的答案,一个用于奇数,一个用于偶数,两者都具有相同的算法

对于奇数:一个指针移动一步,第二个指针移动两个元素作为时间,当第二个元素到达最后一个元素时,第一个指针所在的元素是中间元素。非常容易奇怪。 尝试:1 2 3 4 5

对于偶数:相同,一个指针移动一步,第二个指针移动两个元素作为时间,当第二个元素不能跳转到下一个元素时,第一个指针所在的元素是中间元素。 尝试:1 2 3 4

答案 4 :(得分:0)

LinkedList.Node current = head;
  int length = 0;
  LinkedList.Node middle = head;

  while(current.next() != null){
      length++;
      if(length%2 ==0){
          middle = middle.next();
      }
      current = current.next();
  }

  if(length%2 == 1){
      middle = middle.next();
  }

  System.out.println("length of LinkedList: " + length);
  System.out.println("middle element of LinkedList : " + middle);

答案 5 :(得分:0)

使用大小变量可以保持链接列表的大小。

public class LinkedList {
private Node headnode;
private int size;


public void add(int i){
    Node node = new Node(i);
    node.nextNode = headnode;

    headnode = node;
    size++;
}

public void findMiddleNode(LinkedList linkedList, int middle) {
    Node headnode = linkedList.getHeadnode();
    int count = -1;
    while (headnode!=null){
        count++;

        if(count == middle){
            System.out.println(headnode.data);
        }else {
            headnode = headnode.nextNode;
        }

    }
}


private class Node {
    private Node nextNode;
    private int data;

    public Node(int data) {
        this.data = data;
        this.nextNode = null;
    }
}

public Node getHeadnode() {
    return headnode;
}

public int getSize() {
    return size;
}
}

然后从客户端方法中找到列表大小的中间位置:

public class MainLinkedList {
public static void main(String[] args) {
    LinkedList linkedList = new LinkedList();
    linkedList.add(5);
    linkedList.add(3);
    linkedList.add(9);
    linkedList.add(4);
    linkedList.add(7);
    linkedList.add(99);
    linkedList.add(34);
    linkedList.add(798);
    linkedList.add(45);
    linkedList.add(99);
    linkedList.add(46);
    linkedList.add(22);
    linkedList.add(22);


    System.out.println(linkedList.getSize());

    int middle = linkedList.getSize()/2;

    linkedList.findMiddleNode(linkedList, middle);

}
}

我不知道这是否比两节点方式更好,但是在这里你也不必遍历整个循环。

答案 6 :(得分:0)

使用C#查找链表的中间元素

    static void Main(string[] args)
    {
        LinkedList<int> linked = new LinkedList<int>();
        linked.AddLast(1);
        linked.AddLast(3);
        linked.AddLast(5);
        linked.AddLast(6);
        linked.AddFirst(12);

        Console.WriteLine("Middle Element - "+ListMiddle<int>(linked));
        Console.ReadLine(); }   

public static T ListMiddle<T>(IEnumerable<T> input)
    {
        if (input == null)
            return default(T);

        var slow = input.GetEnumerator();
        var fast = input.GetEnumerator();

        while (slow.MoveNext())
        {
            if (fast.MoveNext())
            {
                if (!fast.MoveNext())
                    return slow.Current;
            }
            else
            {
                return slow.Current;
            }
        }
        return slow.Current;
    }

答案 7 :(得分:0)

以下Java方法查找链接列表的中间位置。它使用两个指针 1)在每次迭代中移动一个的慢指针 2)快速指针,在每次迭代中移动两次 当快速到达列表末尾时,慢速指针将指向中间

public SinglyLinkedListNode getMiddle(SinglyLinkedListNode list) {
        if (list == null)
            return null;
        SinglyLinkedListNode fastPtr = list.next;
        SinglyLinkedListNode slowPtr = list;
        while (fastPtr != null) {
            fastPtr = fastPtr.next;
            if (fastPtr != null) {
                slowPtr = slowPtr.next;
                fastPtr = fastPtr.next;
            }
        }

        return slowPtr;
    }

答案 8 :(得分:0)

对于带有给定头节点和尾节点的指针的双向链表
我们可以同时使用头和尾遍历

p = head;
q = tail;
while(p != q && p->next != q)
{
    p = p->next;
    q = q->prev;
}
return p;

可以引入指向中间节点的指针,但是功能类似于
insertNode和deleteNode必须修改此指针

答案 9 :(得分:0)

使用两个指针方法的中间元素的Python代码:

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

class LinkedList:
    def __init__(self):
        self.head=None

    def printList(self):
        temp=self.head
        while(temp):
            print(temp.data,end=" ")
            temp=temp.next

    def insertAtBeg(self,new_data):
        new_node=Node(new_data)
        if self.head is None:
            self.head=new_node
            return

        new_node.next=self.head
        self.head=new_node

    def findMiddle(self):
        fast_ptr=self.head
        slow_ptr=self.head

        if(self.head is not None):
            while(fast_ptr is not None and fast_ptr.next is not None):
                fast_ptr=fast_ptr.next.next
                slow_ptr=slow_ptr.next
            print('Middle Element is '+ str (slow_ptr.data))

if __name__=='__main__':
    mylist=LinkedList()
    mylist.insertAtBeg(10)
    mylist.insertAtBeg(20)
    mylist.insertAtBeg(30)
    mylist.findMiddle()

输出: 中间元素是20

答案 10 :(得分:0)

@EntityScan(basePackages = {"#{'${scan.packages}'.split(',')}"})

} }

答案 11 :(得分:0)

我正在添加我的解决方案,该解决方案将适用于奇数和偶数个元素场景,例如

1-2-3-4-5中间元素3

1-2-3-4中间元素2,3

它受到与帖子中其他一些答案中提到的相同的快速指针和慢速指针原理的启发。

public class ComplexWidget extends SimpleWidget

} }

答案 12 :(得分:0)

类节点:

# Function to initialise the node object  

def __init__(self, data):  

    self.data = data  

    self.next = None 

LinkedList类:

def __init__(self): 

    self.head = None



def push(self, new_data): 

    new_node = Node(new_data) 

    new_node.next = self.head 

    self.head = new_node 



# Function to get the middle of  

# the linked list 

def printMiddle(self): 

    slow_ptr = self.head 

    fast_ptr = self.head 



    if self.head is not None: 

        while (fast_ptr is not None and fast_ptr.next is not None): 

            fast_ptr = fast_ptr.next.next

            slow_ptr = slow_ptr.next

        print("The middle element is: ", slow_ptr.data) 

驱动程序代码

list1 = LinkedList()

list1.push(5)

list1.push(4)

list1.push(2)

list1.push(3)

list1.push(1) list1.printMiddle()

答案 13 :(得分:-2)

使用“快速”和“慢速”两个指针是愚蠢的。因为运算符接下来使用了1.5n次。没有优化。

  

使用指针保存中间元素可以帮助您。

list* find_mid_1(list* ptr)
{
    list *p_s1 = ptr, *p_s2 = ptr;
    while (p_s2=p_s2->get_next())
    {
        p_s2 = p_s2->get_next();
        if (!p_s2)
            break;
        p_s1 = p_s1->get_next(); 
    }
    return p_s1;
}