重新排列链表的节点,例如奇数索引节点,最后出现

时间:2014-01-29 23:03:21

标签: java algorithm linked-list swap

以下是我在网站上发现的使用LinkedList的问题:

  

编写一个方法移位,重新排列整数列表的元素,方法是移动到列表末尾所有奇数位置的值,否则保留列表顺序。例如,假设变量列表存储以下值:

     

[0, 1, 2, 3, 4, 5, 6, 7]

     

list.shift()的调用;应该将列表重新排列为:

     

[0, 2, 4, 6, 1, 3, 5, 7]

     

在此示例中,原始列表中的值等于它们的位置,并且存在偶数个元素,但情况不一定如此。例如,如果列表存储了以下内容:

     

[4, 17, 29, 3, 8, 2, 28, 5, 7]

     

然后调用list.shift();列表将存储:

     

[4, 29, 8, 28, 7, 17, 3, 2, 5]

     

请注意,值本身是奇数还是偶数无关紧要。重要的是该值是否出现在奇数索引(索引1,3,5等)中。另请注意,否则将保留列表的原始顺序。您可能无法构造任何新节点,并且您可能不使用任何辅助数据结构来解决此问题(没有数组,ArrayList,堆栈,队列,字符串等)。您也可以不更改节点的任何数据字段;你必须通过重新安排列表的链接来解决这个问题。

我首先难以理解这一点。在第一个例子中, [0, 1, 2, 3, 4, 5, 6, 7]

move(index 1) will give [0,2,3,4,5,6,7,1]
move(index 3) will give [0,2,3,5,6,7,1,4]

我已经打破了预期的转变。我不明白这个问题。 关于这个问题的提示以及如何处理这个问题会非常有帮助。

更新:通过理解以下答案实现了这一点:

public void shift() {
    if (front==null)
        return;

    ListNode curr = front;
    ListNode temp = curr.next;
    while (curr.next!=null && curr.next.next != null) {
        curr.next = curr.next.next;
        curr = curr.next;
        temp.next = curr.next;
    }
    curr.next = temp;
    temp.next = null;
}

input: [3, 3, 3, 3, 4]  
expected output: front -> [3] -> [3] -> [4] -> [3] -> [3]
my output: front -> [3] -> [3] -> [4] -> [3]

input: [0, 1, 2, 3, 4, 5, 6, 7]
expected output: front -> [0] -> [2] -> [4] -> [6] -> [1] -> [3] -> [5] -> [7]
expected output: front -> [0] -> [2] -> [4] -> [6] -> [1]

从我的输出中可以看出,我没有正确地重新链接临时节点。即临时节点没有得到更新。但我不知道为什么?

7 个答案:

答案 0 :(得分:1)

您正在考虑在每次移动后基本上将索引重新计算到列表中。

他们真正考虑从列表中移动其他项目,就像它最初存在一样。

预期的难点在于跟踪何时停止重新排列元素。您希望在最初位于列表中的最后一个节点之后停止,但如果您以最明显的方式执行此操作,那么当您到达那里时,它将不再是列表中的最后一个节点。

微妙提示:即使假设单链表无法直接找到最后一个节点,您仍然可以只通过一次遍历列表来完成工作。

这样做有点棘手。在遍历第一个列表时,不是将每个节点添加到原始列表的末尾,而是在遍历原始列表时将这些节点放在单独的临时列表中。当您到达原始列表的末尾时,然后通过将原始列表末尾的空指针更改为指向临时列表的开头(并且因为您',将整个临时列表拼接到原始列表的末尾)到达最后,您将临时列表的最后一个节点中的“下一个”指针设置为NULL)。

这对于数组来说通常是不切实际的,因为你暂时需要为数组中一半元素提供额外的存储空间。但是,对于链接列表,您只需要两个额外的指针:一个用于临时列表的开头,另一个用于临时列表中的最后一个节点。

答案 1 :(得分:0)

您在实施中犯了一个小错误,您不希望每次都temp更新temp.next=curr.next;。您希望将变量保留在列表的开头,然后将变量作为列表的最后一个元素(并且您将下一个临时节点附加到此元素,并且永远不会触及第一个元素)。然后将第一个元素追加到原始列表的末尾。

当你构建一个列表时,你总是保留2个两个指针:一个在列表的开头(所以你可以完全使用它),一个在列表的末尾添加元素。这就是为什么你在O(1)中最后添加元素而你要在n中的O(n)位置添加元素(你需要迭代n个第一个元素)。

Jerry Coffin在他的最后一段中暗示了这一点。

也许您应该看看如何构建列表? http://en.wikipedia.org/wiki/Linked_list(我认为您正在实施简单的链接列表。)

答案 2 :(得分:0)

试试这个: 代码不言自明:如果你不理解,发表评论,我会澄清

public void switchPairs() {
    if (front != null && front.next != null) {
        ListNode current = front.next;
        front.next = current.next;
        current.next = front;
        front = current;
        current = current.next;

        while (current.next != null && current.next.next != null) {
            ListNode temp = current.next.next;
            current.next.next = temp.next;
            temp.next = current.next;
            current.next = temp;
            current = temp.next;
        }
    }
}

答案 3 :(得分:0)

下面的代码片段会生成您要求的确切输出。 阅读内联评论。 干杯!

/**
 * A method that strips the even and odd elements in a Linkedlist
 */
public static void zipper(LinkedList list) {

    LinkedList head = list;
    LinkedList oddHead = head;
    LinkedList evenHead = head.getNext();

    LinkedList oddMove = oddHead;
    LinkedList evenMove = evenHead;

    while (head != null && evenMove != null && oddMove != null) {

        oddMove.next = head.next.next; // set the link to appropriate
                                        // position for odd list
        oddMove = oddMove.next; // move the pointer to new head of odd list
        head = head.next; // move original head
        if (head != null) {
            evenMove.next = head.next; // set the link to appropriate
                                        // position for even list
            evenMove = evenMove.next; // move the pointer to new head of
                                        // even list
        }

    }

    LinkedList temp2 = oddHead;

    while (temp2.next != null) {
        //System.out.println(temp2.elem);
        temp2 = temp2.next;
    }

    temp2.next = evenHead;


        System.out.println("----------------elems------------------");
    while (oddHead != null) {
        System.out.println(oddHead.elem);
        oddHead = oddHead.next;
    }

    System.out.println("------------------------------------------------");}

答案 4 :(得分:0)

这是Java实现

public static LinearNode<Integer> seperateEvenAndOddIndexNodes(LinearNode<Integer> head) {
    LinearNode<Integer> prevNode =null, currentNode = head, tail = head, nextNode;
    int length = length(head),index = 0;

    if (length < 3) {
        return head;
    }

    while (tail != null && tail.next() != null) {
        tail = tail.next();         
    }
    while (currentNode != null && index < length) {
        nextNode = currentNode.next();
        if (index % 2 == 1) {
            LinearNode<Integer> temp = currentNode;
            tail.next(temp);
            tail = temp;
            prevNode.next(nextNode);
            currentNode = prevNode;
            temp.next(null);
        }
        prevNode = currentNode;
        currentNode = nextNode;
        index++;
    }

    return head;
}

这是单元测试用例

@Test
public void seperateEvenAndOddIndexesTest() {
    LinearNode<Integer> head = buildLinkedList(1,2,3,4,5,6);
    head = LinkedListUtil.seperateEvenAndOddIndexNodes(head);
    assertLinkedList(head, 1,3,5,2,4,6);

    head = buildLinkedList(1);
    head = LinkedListUtil.seperateEvenAndOddIndexNodes(head);
    assertLinkedList(head, 1);

    head = buildLinkedList(1, 2);
    head = LinkedListUtil.seperateEvenAndOddIndexNodes(head);
    assertLinkedList(head, 1, 2);

    head = buildLinkedList(1, 2, 3);
    head = LinkedListUtil.seperateEvenAndOddIndexNodes(head);
    assertLinkedList(head, 1, 3, 2);
}

答案 5 :(得分:0)

这是O(n)的工作代码: 想法是你传递对空列表q的引用以及原始列表。切片p->接下来,将其追加到列表q,其尾部始终指向原始列表p的开头。 请注意,此解决方案仅适用于在所有节点之前放置偶数节点的情况。您可以轻松更改逻辑,反之亦然。

int main() {

    NODEPTR list = create_list(10);
    NODEPTR q = NULL;  
    odd_even_part(list, &q);

    printf("\n Here is list after partitionining and rearranging :\n");
    recursive_print(q);

    return 0;

}
/* Use recursion to build rearranged list q */

NODEPTR odd_even_part(NODEPTR p, NODEPTR* q) {
    NODEPTR temp = NULL;
    if(p == NULL || p->next == NULL) {
        return p;
    }
    else {
        temp = p->next;
        p->next = temp->next;
        if((*q) == NULL) {
            (*q) = temp;
            temp->next = p;
        }else {
            temp->next = (*q)->next;
            (*q)->next = temp;
        }

        odd_even_part(p->next,&temp);
    }
}

答案 6 :(得分:0)

可以通过将大列表重组为两个较小的列表来解决此问题,一个较小的列表具有偶数索引元素,而另一个具有奇数索引元素。创建这两个子列表后,将它们合并在一起,并将front设置为合并列表的开头。

为了最终合并两个列表,您将需要四个变量。指向每个子列表前面的两个变量分别称为evenFrontoddFront,以及两个变量来循环访问子列表,分别称为evenodd

even初始化为front(由于列表为零索引,因此列表中的第一个偶数索引元素位于索引为零,也称为front)并初始化{ {1}}到odd(出于相同的原因,列表中的第一个奇数索引元素位于索引1,front.next之后的下一个元素)。

这是我的代码。

front