【问题标题】:Reverse every k nodes of a linked list反转链表的每k个节点
【发布时间】:2011-10-31 13:47:41
【问题描述】:

我正在准备一次技术面试,我一直在编写这个程序来反转链表的每 k 个节点。

例如

1->2->3->4->5->6 //Linked List
2->1->4->3->6->5 //Output for k=2

编辑:

这是我的代码。我只得到 6->5 作为输出。

struct node* recrev(struct node* noode,int c)
{
 struct node* root=noode,*temp,*final,*prev=NULL;
 int count=0;
 while(root!=NULL && count<c)
 {
  count++;
  temp=root->link;
  root->link=prev;
  prev=root;
  root=temp;
 }
 if(temp!=NULL)
   noode->link=recrev(temp,c);
 else
   return prev;

}

感谢任何帮助。谢谢。

编辑:我尝试如下实现 Eran Zimmerman 的算法。

struct node* rev(struct node* root,int c)
{
 struct node* first=root,*prev,*remaining=NULL;
 int count=0;
 while(first!=NULL && count<c)
 {

    count++;
    prev=first->link;
    first->link=remaining;
    remaining=first;
    first=prev;
 }
 return remaining;
}
struct node* recc(struct node* root,int c)
{
 struct node* final,*temp,*n=root,*t;
 int count=0;
 while(n!=NULL)
 {
       count=0;
       temp=rev(n,c);
       final=temp;


    while(n!=NULL && count<c)
    {   
     printf("inside while: %c\n",n->data);  // This gets printed only once
     if(n->link==NULL) printf("NULL");    //During first iteration itself NULL gets printed
        n=n->link;
        final=final->link;
        count++;
    }

 }
 final->link=NULL;
 return final;
}

【问题讨论】:

标签: c algorithm linked-list


【解决方案1】:

是的,我从来都不喜欢递归,所以这是我使用迭代的方法:

  public Node reverse(Node head, int k) {
       Node st = head;
       if(head == null) {
         return null;
       }

       Node newHead = reverseList(st, k);
       st = st.next;  

       while(st != null) {
         reverseList(st, k);
         st = st.next;
       } 

       return newHead

  }


 private Node reverseList(Node head, int k) {

      Node prev = null;
      Node curr = head;
      Node next = head.next;

      while(next != null && k != 1){
       curr.next = prev;
       prev = curr;
       curr = next;
       next = next.next;
       --k;
      }
      curr.next = prev;

      // head is the new tail now.
      head.next = next;

      // tail is the new head now.
      return curr;
 }

【讨论】:

    【解决方案2】:
    public class ReverseEveryKNodes<K>
    {
          private static class Node<K>
          {
            private K k;
            private Node<K> next;
    
            private Node(K k)
            {
                this.k = k;
            }
          }
    private Node<K> head;
    private Node<K> tail;
    private int size;
    
    public void insert(K kk)
    {
        if(head==null)
        {
            head = new Node<K>(kk);
            tail = head;
        }
        else
        {
            tail.next = new Node<K>(kk);
            tail = tail.next;
        }
        size++;
    }
    
    public void print()
    {
        Node<K> temp = head;
        while(temp!=null)
        {
            System.out.print(temp.k+"--->");
            temp = temp.next;
        }
        System.out.println("");
    }
    
    public void reverse(int k)
    {
        head = reverseK(head, k);
    }
    
    Node<K> reverseK(Node<K> n, int k)
    {
        if(n==null)return null;
    
        Node<K> next=n, c=n, previous=null;
        int count = 0;
        while(c!=null && count<k)
        {
            next=c.next;
            c.next=previous;
            previous=c;
            c=next;
            count++;
        }
        n.next=reverseK(c, k);
        return previous;
    }
    
    public static void main(String[] args)
    {
        ReverseEveryKNodes<Integer> r = new ReverseEveryKNodes<Integer>();
        r.insert(10);
        r.insert(12);
        r.insert(13);
        r.insert(14);
        r.insert(15);
        r.insert(16);
        r.insert(17);
        r.insert(18);
        r.print();
        r.reverse(3);
        r.print();
    }
    }
    

    【讨论】:

      【解决方案3】:

      以下解决方案使用额外的空间来存储指针,并分别反转每个列表块。最后,新列表建立。当我测试时,这似乎涵盖了边界条件。

      template <typename T>
      struct Node {
      T data;  
      struct Node<T>* next;
      Node()  {  next=NULL; } 
      };
      template <class T>
      void advancePointerToNextChunk(struct Node<T> * & ptr,int  & k)  {
      int count =0;  
      while(ptr && count <k )  {
          ptr=ptr->next; 
          count ++; 
      }
      k=count;}
      
      /*K-Reverse Linked List */
      template <class T>  
       void kReverseList( struct Node<T> * & head,  int k){ 
       int storeK=k,numchunk=0,hcount=0;
       queue < struct Node<T> *> headPointerQueue;  
       queue <struct Node<T> *>  tailPointerQueue; 
      
       struct Node<T> * tptr,*hptr;
       struct Node<T> * ptr=head,*curHead=head,*kReversedHead,*kReversedTail;
       while (ptr) {
       advancePointerToNextChunk(ptr,storeK);
       reverseN(curHead,storeK,kReversedHead,kReversedTail);
       numchunk++; 
       storeK=k; 
       curHead=ptr;
       tailPointerQueue.push(kReversedTail),headPointerQueue.push(kReversedHead); 
       }
       while( !headPointerQueue.empty() ||  !tailPointerQueue.empty() )  {
          if(!headPointerQueue.empty()) {
              hcount++;  
              if(hcount == 1) { 
                  head=headPointerQueue.front(); 
                  headPointerQueue.pop();
              }
              if(!headPointerQueue.empty()) {
              hptr=headPointerQueue.front(); 
              headPointerQueue.pop(); 
              }
          }
          if( !tailPointerQueue.empty() ) {
              tptr=tailPointerQueue.front();  
              tailPointerQueue.pop(); 
          }
          tptr->next=hptr;  
       }
       tptr->next=NULL;}
      
       template <class T> void reverseN(struct Node<T> * & head, int k, struct Node<T> * &   kReversedHead, structNode<T> * & kReversedTail ) {
        struct Node<T> * ptr=head,*tmp;  
        int count=0;
        struct Node<T> *curr=head,*nextNode,*result=NULL; 
        while(curr && count <k) {
            count++; 
            cout <<"Curr data="<<curr->data<<"\t"<<"count="<<count<<"\n"; 
            nextNode=curr->next;  
            curr->next=kReversedHead; 
            kReversedHead=curr;
            if(count ==1 )  kReversedTail=kReversedHead; 
            curr=nextNode;
        }}
      

      【讨论】:

        【解决方案4】:

        这是一个伪代码。

        temp = main_head = node.alloc ();
        while ( !linked_list.is_empty () )
        {
            push k nodes on stack
            head = stack.pop ();
            temp->next = head;
            temp = head;
            while ( !stack.empty () )
            {
                temp->next = stack.pop ();
                temp = temp->next;
            }
        }
        

        我已经对此代码进行了演示实现。请原谅凌乱的实施。这适用于k 的任何值。每个k 大小的段在内部循环中分别反转,不同的段在进入内部循环之前在外部循环中相互链接。 temp 跟踪 k 大小的子列表的最后一个节点,head 保存下一个子列表的下一个值,我们将它们链接起来。使用显式堆栈进行反转。

        #include <stdio.h>
        #include <stdlib.h>
        
        typedef struct _node {
          int a;
          struct _node *next;
        } node_t;
        
        typedef struct _stack {
          node_t *arr[128];
          int top;
        } stack_t;
        
        void stk_init (stack_t *stk)
        {
          stk->top = -1;
        }
        
        void push (stack_t *stk, node_t *val)
        {
          stk->arr[++(stk->top)] = val;
        }
        
        node_t *pop (stack_t *stk)
        {
          if (stk->top == -1)
           return NULL;
          return stk->arr[(stk->top)--];
        }
        
        int empty (stack_t *stk)
        {
          return (stk->top == -1);
        }
        
        int main (void)
        {
          stack_t *stk = malloc (sizeof (stack_t));
          node_t *head, *main_head, *temp1, *temp;
          int i, k, n;
        
          printf ("\nEnter number of list elements: ");
          scanf ("%d", &n);
          printf ("\nEnter value of k: ");
          scanf ("%d", &k);
        
          /* Using dummy head 'main_head' */
          main_head = malloc (sizeof (node_t));
          main_head->next  = NULL;
          /* Populate list */
          for (i=n; i>0; i--)
          {
            temp = malloc (sizeof (node_t));
            temp->a = i;
            temp->next = main_head->next;
            main_head->next = temp;
          }
        
          /* Show initial list */
          printf ("\n");
          for (temp = main_head->next; temp != NULL; temp = temp->next)
          {
            printf ("%d->", temp->a);
          }
        
          stk_init (stk);
        
          /* temp1 is used for traversing the list
           * temp is used for tracing the revrsed list
           * head is used for tracing the sublist of size 'k' local head
           * this head value is used to link with the previous
           * sublist's tail value, which we get from temp pointer
           */
          temp1 = main_head->next;
          temp = main_head;
          /* reverse process */
          while (temp1)
          {
            for (i=0; (temp1 != NULL) && (i<k); i++)
            {
              push (stk, temp1);
              temp1 = temp1->next;
            }
            head = pop (stk);
            temp->next = head;
            temp = head;
            while (!empty (stk))
            {
              temp->next = pop (stk);
              if (temp->next == NULL)
                break;
              temp = temp->next;
            }
          }
          /* Terminate list with NULL . This is necessary as
           * for even no of nodes the last temp->next points
           * to its previous node after above process
           */
          temp->next = NULL;
        
          printf ("\n");
          for (temp = main_head->next; temp != NULL; temp = temp->next)
          {
            printf ("%d->", temp->a);
          }
        
          /* free linked list here */
        
          return 0;
        }
        

        【讨论】:

          【解决方案5】:

          我会这样做:

          init curr (node pointer) to point to the beginning of the list.
          while end of list is not reached (by curr):
          - reverse(curr, k)
          - advance curr k times
          

          而reverse是一个函数,从curr开始反转前k个元素。

          这可能不是最优雅或最有效的实现,但它可以工作并且非常简单。

          回答您添加的代码:

          你返回了 prev,它在不断进步。您应该返回列表的开头。

          【讨论】:

          • 我尝试实现您的算法,但没有成功。一旦我将列表反转到 k 个节点,我的原始列表就会丢失并且无法继续循环。如果你能实现它,请分享代码..
          • 请发布您尝试过的代码,识别单个问题可能比从头开始重写代码更快。
          【解决方案6】:

          (我假设这是一个单链表。)您可以保留一个临时指针(我们称之为nodek)并在while 循环中将其推进k 次。这将花费 O(k)。现在您有了一个指向列表开头和子列表最后一个元素的指针。要在此处反转,您从 O(1) 的头部删除并添加到 O(1) 的 nodek。对所有元素都这样做,所以这又是 O(k)。现在将 root 更新为 nodek,并再次在 nodek 上运行 while 循环(以获取 nodek 的新位置)并再次重复整个过程。请记住在此过程中进行任何错误检查。 此解决方案将以 O(n) 运行,只有 O(1) 额外空间。

          【讨论】:

            【解决方案7】:

            我喜欢你的递归,虽然它可能不是最好的解决方案。从您的代码中我可以看出您在设计时认为它很深。你离答案只有一步之遥。

            原因:您忘记在递归案例中返回新的root 节点。

            if(temp!=NULL)
               noode->link=recrev(temp,c);
               // You need return the new root node here
               // which in this case is prev:
               // return prev;
             else
               return prev;
            

            【讨论】:

            • 我不明白你。你能把修改后的代码贴在这里,以便我更好地理解。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-25
            • 2016-07-09
            • 2018-07-28
            • 1970-01-01
            • 2023-03-08
            相关资源
            最近更新 更多