在C中反转双链表的元素
Posted
技术标签:
【中文标题】在C中反转双链表的元素【英文标题】:Reversing the elements of a double linked list in C 【发布时间】:2013-12-16 11:21:18 【问题描述】:这是我的方法——在列表的开头保留一个指针,在列表的末尾保留一个指针。将头指针向前推进,将尾指针向后推进,直到它们指向相同。 在转发之前交换值。该函数在调用时会抛出分段错误。为什么会这样? 这是我的列表节点结构
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");
【问题讨论】:
段错误在哪一行? 我是初学者,如何查看segfault在哪一行? 最好的方法是在调试器中运行它。我想如果你现在不想学习如何使用调试器,你甚至可以在每一行后面加上一个printf
,看看哪个是最后打印的。
你需要给一个小的完整的复制器。所以有人可以在不做任何修改的情况下编译和运行。问题可能不在上面的代码中,而是在其他地方。
我在调试器中运行它。它在 while 语句中显示分段错误
【参考方案1】:
通过颠倒列表的顺序,您的意思是交换所有 item 的 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 仍然是列表的开头。
再见,
弗朗西斯
【讨论】:
感谢您的回答。虽然,这是一个更好的逻辑,但我使用的是不同的逻辑,如问题中所述。在我的逻辑中,列表的链接将相同,root 将相同。它只是交换数字,就像一个数组 正如我在回答中指出的那样,*root 在您的程序运行后将不相同。【参考方案2】:很难判断这段代码在哪里遇到了分段错误。但是,如果您的调试器说它在编写 while
语句的那一行引发了错误:
while(((*root)->next != tail->prev) || ((*root)->next != tail))//one for even no. of nodes and one for odd no.of nodes
那么几乎可以肯定,root
、*root
或 tail
在此时为 NULL 或未初始化的指针。
一种可能性:如果你用一个只包含一个元素的链表调用这个函数,那么tail
和*root
将在这个循环的开始指向同一个元素。这个条件的编写方式,程序会认为它需要继续反转元素,并将继续向后移动tail
和向前移动*root
。由于程序从不检查是*root == NULL
还是tail == NULL
,最终它会直接从列表的末尾走出来并尝试取消引用NULL 指针,这将导致分段错误。
在移动指针和解除引用之间检查指针是否为 NULL 是一个非常好的主意。考虑一下如果调用一个包含 0 个元素的列表、包含 1 个元素的列表等的函数会发生什么,这通常也很有帮助。
【讨论】:
【参考方案3】:首先,我必须真的坚持你使用哨兵节点 对于您的链表,它大大简化了代码。
一旦你转换为使用哨兵节点,创建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
【讨论】:
【参考方案4】:我编写了这个函数,用递归方法反转双链表。
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;
【讨论】:
【参考方案5】:结构节点
int data;
struct node *prev;
struct node *next;
;
typedef 结构节点 *list; //只是使用 typedef 来缩短内容
list temp=NULL,head=NULL,last=NULL,r=NULL,p=NULL;
/这里使用了创建函数,所以 last 和 head 现在分别指向最后一个节点和第一个节点/
我的倒车函数(可能是最短的)=>
最后一个=头;
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=最后一个;
while(p->prev!=NULL)
p=p->prev;
头=p;
【讨论】:
以上是关于在C中反转双链表的元素的主要内容,如果未能解决你的问题,请参考以下文章