2009-11-17 37 views
1

如何找到鏈表的中間,當我們沒有被告知它的大小,它必須只使用一個循環,只有一個指針來進行的。中間鏈表

+1

這是整個問題嗎?你允許使用遞歸嗎? – rlbond 2009-11-17 04:36:04

+1

這是一個單鏈接還是雙鏈表? – paxdiablo 2009-11-17 04:36:16

+6

如何使用只有一個互聯網連接和只有一個stackoverflow網站找到我的作業問題的答案... – 2009-11-17 04:37:58

回答

13

LinkedList * llist = getLList(); // the linked list 
Node * node = llist.head; 

while (node) { 
    node = node.next; 
    if (node) { 
     node = node.next; 
     llist.remove(llist.head); 
    } 
} 
// now llist.head is (er, um... was) the middle node. 
// hope you didn't need the rest of the list. 
+2

哈哈!太棒了! – rlbond 2009-11-17 04:51:35

+0

但是你正在使用兩個指針。肯定是「e」,絕對是「頭」。 wrang-wrang的解決方案似乎對我來說是一樣的... 我認爲這個問題沒有答案。你不能用一個指針來處理L1列表(因爲當你移動它時,你會鬆開你的頭(以及...列表頭)) – SadSido 2009-11-17 08:52:56

+3

@SadSido:顯然,如果我有一個鏈表,我有一堆指針,包括頭部。除了那些已經在列表中的人之外,我認爲這個問題意味着一個指針。 – 2009-11-17 13:06:14

8
Node *m,*e,*head; /* head is given */ 
m=e=head; 
while(e) { 
    e=e->next; 
    if (e) { 
    e=e->next; 
    m=m->next; 
    } 
} 
/* now m is the middle node */ 

對不起,我不得不用兩個指針:)


添加給你的答案,因爲一個小調整降低指針的數量爲1。我希望你不介意:

Node m,*e,*head; /* head is given */ 
e = head; 
if (e) m = *e; 
while(e) { 
    e = e->next; 
    if (e) { 
    e = e->next; 
    m = *(m.next); 
    } 
} 
/* now m is the middle node */ 
+3

嗯,當你作弊時,它並不是一個挑戰。 – rlbond 2009-11-17 04:39:19

+1

@rlbond:但它仍然非常聰明。 – Thilo 2009-11-17 04:45:16

+0

@rlbond:如果你想到一個更好的解決方案,建議它而不是抱怨,在我看來最合理的解決方案。顯然,在偶數節點的情況下,中間節點是非常值得商榷的。 – 2009-11-17 13:53:02

2

嗯,這是一種破解,因爲它在功能上等同於2個循環。但是,它仍然只有1個循環。

Node* middle(Node* const begin) 
{ 
    Node* current = begin; 
    bool size_known = false; 
    int size = 0; 
    while (true) 
    { 
     if (!size_known) 
     { 
      if (current) 
      { 
       ++size; 
       current = current->next; 
      } 
      else 
      { 
       current = begin; 
       size_known = true; 
      } 
     } 
     else 
     { 
      if (size <= 1) 
       return current; 
      current = current->next; 
      size -= 2; 
     } 
    } 
} 
+0

如何使用額外的布爾和一個額外的int不同於使用一個額外的指針? – Thilo 2009-11-17 04:48:01

1

怎麼看我的代碼。它適用於我的FC9 x86_64的正確,功能「中間()」是你想要什麼:

static struct node *middle(struct node *head) 
{ 
     struct node *mid = head; 
     int flag = 0; 
     while (NULL != head) { 
       head = head->next; 
       flag = !flag; 
       if (flag) { 
         mid = mid->next; 
       } 
     } 
     return mid; 
} 

編輯:刪除代碼,除了中間的()。

+3

你也在使用2個指針(你正在修改'head')。 – rlbond 2009-11-17 04:57:32

+1

是的,這與wrang-wrang的解決方案基本相同。 – Thilo 2009-11-17 05:01:43

0

使用提供的頭指針對列表進行迭代,然後增加一個允許的指針(我假設您的模糊問題是允許一個指針除了傳入的指針)每兩個增量的頭指針。

Node* middle(Node* head) 
{ 
    Node* middle = head; 
    while (head != NULL) { 
     head = head->next; 

     if (head->next != NULL) { 
      head = head->next; 
      middle = middle->next; 
     } 
    } 
    return middle; 
} 

這裏有一些邊緣情況被忽略(比如什麼是偶數個元素的列表中間)。

1

我們可以在這種情況下使用跳躍列表:

1)在鏈表遍歷每個節點使奇數節點的跳躍列表。時間:O(n)的空間:O(N/2)

2)現在,當你到達列表的末尾除以2 legnth加1得到中間元素的索引。

3)搜索在跳躍列表O(LOGN)時間的索引。

因此,該算法的總的時間複雜是:

爲O(n)(1個遍歷)+ O(LOGN)(搜索跳轉列表)= O(n)的 空間複雜度:O(N/2)

請回復,如果這是低效....

0

我在IBM ISL浦那類似的問題。問:「如何查找單鏈表的中間節點」。 我回答 答:「拿兩根指針開始在頭部和移動在一步一個指針,並在兩個步驟的另一指針」。採訪者說,這是最簡單的解決方案。問:告訴我你將如何遍歷而不使用2個指針。提示是「使用編譯器屬性」。

有誰知道如何使用編譯器屬性查找中間節點?