给出块大小时反转单链表

时间:2011-08-08 13:05:32

标签: algorithm linked-list space-complexity

有一个单独连接的链表,并给出了一个块大小。例如,如果我的链表是1->2->3->4->5->6->7->8-NULL而我的块大小是4,那么反转第一个4元素和然后是第二个4个元素。问题的输出应该是4->3->2->1->8->7->6->5-NULL

我正在考虑将链表分成大小为4的段,然后将其反转。 但是那样我就不得不使用很多额外的节点了。 空间复杂性应保持在最低限度。

如果有人能够提供更好的解决方案,将额外节点的使用保持在最低限度,那将是非常值得注意的。

3 个答案:

答案 0 :(得分:2)

我试过这个......似乎工作得很好......

node* reverse(node* head) // function to reverse a list
{
    node* new_head = NULL;
    while(head != NULL)
    {
        node* next = head->next;
        head->next = new_head;
        new_head = head;
        head = next;
    }
    return new_head;
}

node* reverse_by_block(node* head, int block)
{
    if(head == NULL)
            return head;

    node* tmp = head;
    node* new_head = head;
    node* new_tail = NULL;

    int count = block;
    while(tmp != NULL && count--)
    {
        new_tail = tmp;
        tmp = tmp->next;
    }

    new_tail->next = NULL;
    new_tail = new_head;
    new_head = reverse(new_head);
    new_tail->next = reverse_by_block(tmp,block);

    return new_head;
}

答案 1 :(得分:0)

你可以在接下来的3次中推进当前元素的交换:1234,2134,2314,2341。然后再做两次得到3421.然后一次得到4321.然后前进4步并用下一个块重复该过程

答案 2 :(得分:0)

这可以在线性时间内完成,具有恒定的空间。 以下是简要说明:

  1. 按块大小

    将链表拆分为两部分
    
    int split(node* head, node** listA, node** listB size_t block_size)
    {
    node* cur = head;
    
    while(block_size && cur)
    {
       cur = cur->next;
       --block_size;
    }
    if(!cur) { /* error : invalid block size */ return -1; }
    *listA = head;
    *listB = cur->next;
    cur->next = NULL; /* terminate list A */
    return 0;
    }
    
  2. 反转两个子部分,(使用非递归线性时间,常量空间函数)

    
    reverse(listA);
    reverse(listB);
    
  3. 链接它们以获得所需的链接列表。

    
    cur = *listA;
    /* goto last but one element of listA */
    while(cur->next) cur = cur->next; 
    cur->next = *listB;