反转链表的每个k个节点

时间:2011-08-21 12:03:44

标签: c algorithm linked-list

我正在准备进行技术面试,我一直在编写这个程序来反转链表的每个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;
}

7 个答案:

答案 0 :(得分:5)

是的,我从未成为递归的粉丝,所以这是我使用迭代拍摄它:

  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;
 }

答案 1 :(得分:2)

这是伪代码。

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;
}

答案 2 :(得分:1)

我会做这样的事情:

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,这是不断前进的。你应该返回列表的开头。

答案 3 :(得分:1)

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

原因:您忘记在递归案例中返回新的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;

答案 4 :(得分:0)

(我假设这是一个单链表。)你可以保留一个临时指针(让我们称之为nodek)并在while循环中前进k次。这将需要O(k)。现在,您有一个指向列表开头和子列表最后一个元素的指针。要在此处反转,请从头部移除O(1)并添加到nodek,即O(1)。对所有元素执行此操作,因此再次为O(k)。现在将root更新到nodek,然后再次在nodek上运行while循环(获取nodek的新位置)并再次重复整个过程。记得在整个过程中进行任何错误检查。 该解决方案将在O(n)处运行,仅有O(1)额外空间。

答案 5 :(得分:0)

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

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;
  }}

答案 6 :(得分:0)

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();
}
}