在C中反转双链表的元素

时间:2013-11-30 11:30:54

标签: c linked-list segmentation-fault reverse

这是我的方法 - 在列表的开头保持一个指针,在列表的末尾保持一个指针。向前移动头指针,向后移动尾指针,直到它们指向相同的位置。 在转发之前交换值。函数在调用时抛出一个分段错误。为什么会这样? 这是我对列表节点的结构

struct dll
{
 int number;
 struct dll *next;
 struct dll *prev;
};

这是我反转列表和主要

的功能
    int count=0;
void reverse(struct dll **root)
{
 int temp;
 struct dll *tail=NULL;
 struct dll *temproot=NULL;
 temproot =(*root);
 for(;(temproot)->next !=NULL;(temproot)=(temproot)->next); //traversing to the end
 tail= temproot;
 while(((*root)->next != tail->prev) || ((*root)->next != tail))//one for even no. of nodes and one for odd no.of nodes
 {
  temp=(*root)->number; //swapping the numbers
  (*root)->number=tail->number;
  tail->number=temp;
  (*root)=(*root)->next;
  tail=tail->prev;
 } //even after they are same, values need to be changed one last time
   temp=(*root)->number;
  (*root)->number=tail->number;
  tail->number=temp;
  (*root)=(*root)->next;
  tail=tail->prev;
}
void insert(struct dll **root,int num)
{
 struct dll *temp;
 if(count==0)
 {
  if((*root)==NULL)  
  {
  (*root)=(struct dll *)malloc(sizeof(struct dll));
  (*root)->next=NULL;
  (*root)->prev=NULL;
  (*root)->number=num;
  count++;
  printf("\n%d",count);
  }
 }
 else if((*root)->next==NULL) 
  {
  temp=(struct dll *)malloc(sizeof(struct dll));
  temp->next=NULL;
  temp->prev=(*root);
  temp->number=num;
  (*root)->next=temp;
  count++;
  printf("\n%d",count);
  }
 else
 {
  insert(&(*root)->next,num);
 }

}
main()
{
 struct dll *head=NULL;
 int i,n,num;
 while(1)
 {
  printf("Enter 1 for insert, 3 for reverse, 0 for exit\n");
  scanf("%d",&n);
  switch(n)
  {
   case 1:printf("Enter number\n");
      scanf("%d",&num);
      insert(&head,num);
      break;
   case 3:reverse(&head);break;
   case 0:exit(0);
   default:printf("Enter correct value\n");
  }
 }

}

5 个答案:

答案 0 :(得分:0)

通过颠倒列表的顺序,你的意思是交换所有项目的next和prev指针吗?这段未经检查的代码可以解决这个问题:

void reverse(struct dll **root)
{
  struct dll *buff=NULL;
  struct dll *start=*root;

  unsigned char stop=0;
  while(stop==0){
   if(*root==NULL){
    stop=1;
    break;
   }
   buff=(*root)->prev;
   (*root)->prev=(*root)->next;
   (*root)->next=buff;

   *root=(*root)->prev;//the next to treat is the previous one now
   if(*root==start){
    //this test handle the case of "looping" double linked list
    stop=1;
    break;
  }
 }
}

此代码假定* root是开始时列表的开头。最后,* root仍然是列表的开头。

再见,

弗朗西斯

答案 1 :(得分:0)

很难说这段代码在哪里遇到分段错误。但是如果你的调试器说它在编写while语句的行上引发了错误:

 while(((*root)->next != tail->prev) || ((*root)->next != tail))//one for even no. of nodes and one for odd no.of nodes

然后几乎可以肯定root*roottail为NULL或者此时是未初始化的指针。

一种可能性:如果使用仅包含一个元素的链接列表调用此函数,则tail*root将指向此循环开头的相同元素。编写此条件的方式,程序将认为它需要继续反转元素并继续向前移动tail并向前移动*root。由于程序从不检查是否*root == NULLtail == NULL,因此它最终将从列表的末尾开始走,并尝试取消引用NULL指针,这将导致分段错误。

在移动指针和解除引用指针之间检查指针是否为NULL是一个非常好的主意。如果你调用一个包含0个元素列表的函数,列表中包含1个元素等,那么通常会有所帮助。

答案 2 :(得分:0)

首先,我必须真的坚持你使用岗哨节点 对于您的链接列表,它简化了代码很多

转换为使用哨兵节点后,创建reverse
变得相当微不足道:

struct dll* prev = sentry;

struct dll* curr = sentry->next;
if(curr==sentry) return; // empty list dont need reversing

struct dll* next = curr->next;
if(next==sentry) return; // list size 1 is already its reverse

while( curr != sentry )
{
    // reverse links
    prev->prev = curr;
    curr->next = prev;
    // move to next
    prev = curr;
    curr = next;
    next = next->next;
}

// close loop (first item is the one we found last)
sentry->next = prev;
prev->prev = sentry;

如果您需要一个哨兵节点如何工作的示例,您可以查看here

答案 3 :(得分:0)

我编写了这个函数,用递归方法反转双链表。

void Node::Swap(){
 if(m_pNext != NULL){
   m_pNext->Swap();
   m_pNext->m_pNext = this;
 }
}

void List::Reverse(){
  if(m_pHead!=NULL){
    m_pHead->Swap();
    m_pHead->SetNext(NULL);
  }
  Node* pTemp=m_pHead;
  m_pHead = m_pTail;
  m_pTail = pTemp;
}

答案 4 :(得分:-1)

struct node {

         int data;


         struct node *prev;


         struct node *next;


       };

typedef struct node * list; //只使用typedef来缩短内容

list temp = NULL,head = NULL,last = NULL,r = NULL,p = NULL;

/ 这里使用了创建函数,所以最后和head现在分别指向last和first节点 /

我的逆转功能(可能是最短的)=>

{

最后=头;

R =头;

而(R!= NULL)

{

  temp=r->next;


  r->next=r->prev;


  r->prev=temp;  //swapping next and previous using temp


  r=r->prev; //since now values swapped so reverse traversing

}

P =最后;

而(对GT;!PREV = NULL)

{

  p=p->prev;

}

头= P;

}