我有以下C代码,它返回链表的反向。
虽然它会反转链表,但我从来没有得到反向链表的头部,因为restofElements
节点被覆盖了。
S *reverseRecursive(S *headref) {
S *firstElement = NULL;
S *restOfElements = NULL;
if (headref==NULL) {
return ;
}
firstElement = headref;
restOfElements = headref->next;
if (restOfElements == NULL)
return headref;
reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
headref = restOfElements;
return headref;
}
如何将反向链表节点的头部返回到调用程序?
答案 0 :(得分:1)
如果要更改头指针,则必须通过引用(作为指针)传递它。应修改原型以接收头部为S **。
S *reverseRecursive(S **headref);
答案 1 :(得分:1)
反向列表的头部等于以restOfElements
开头的反向列表的头部(因为原始headref
必须成为反向列表的最后一个元素)。所以存储震荡调用的结果应该这样做(正如Jim在他的评论中已经建议的那样):
...
headref = reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
/* headref = restOfElements; that's wrong */
return headref;
答案 2 :(得分:1)
可能更接近。
S *reverseRecursive(S *headref)
{
S *firstElement = NULL;
S *restOfElements = NULL;
S *new_head = NULL;
if (headref==NULL)
{
return ;
}
firstElement = headref;
restOfElements = headref->next;
if (restOfElements == NULL)
return headref;
new_head = reverseRecursive(restOfElements);
restOfElements->next = new_head;
return restOfElements;
}
答案 3 :(得分:1)
谢谢大家。我稍微修改了一下它现在有效。让我知道你的意见。 new_head是一个全局变量。
S *reverseRecursive(S *headref)
{
S *firstElement = NULL;
S *restOfElements = NULL;
if (headref==NULL)
{
return ;
}
firstElement = headref;
if (headref->next == NULL)
return headref;
else
restOfElements = headref->next;
reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
if(new_head == NULL ) //just dont take it ervery time
new_head = restOfElements;
return new_head;
}
答案 4 :(得分:1)
$ gcc -std = c99 -Wall -Wextra reverse.c
#include <stdlib.h>
#include <stdio.h>
typedef struct list {
struct list* next;
int data;
} S;
void print_list(S* list) {
if (list == NULL) { printf("NULL\n"); return; }
printf("%d ", list->data);
print_list(list->next);
}
S* reverse_aux(S* list, S* tail) {
// invalid arg
if (list == NULL) { return NULL; }
// base case
if (list->next == NULL) {
list->next = tail;
return list;
}
// general case
S* tmp = list->next;
list->next = tail;
return reverse_aux(tmp, list);
}
S* reverse(S* list) { return reverse_aux(list, NULL); }
int main(int argc, char* argv[]) {
// build a list with which to test
S a[10];
for (unsigned i = 0; i < sizeof(a)/sizeof(S); ++i) {
a[i].data = i;
a[i].next = &a[i+1];
}
a[sizeof(a)/sizeof(S) - 1].next = NULL;
S* list = &a[0];
print_list(list);
list = reverse(list);
print_list(list);
return 0;
}
实际上,由于反向是破坏性的(它改变了它的论点),更好的界面设计可能是
void reverse(S** plist);
reverse(&list);
答案 5 :(得分:0)
因此有两种方法可以递归地反转列表。
首先,一些设置。让我们轻松加载链表 字符串和打印它们,所以我们可以确保这些东西工作:
// linked_list.c
#include <stdio.h>
#include <stdlib.h>
// a linked lis of strings
typedef struct S {
struct S * next;
char * val;
} S;
// print out the list
void showS(char * const name, S * head) {
printf("%s: (", name);
while (head){
printf(" ");
printf("%s",head->val);
head = head->next;
printf( "%c", head ? ',' : ' ' );
}
printf(")\n");
}
// convert an array of strings into a linked list of strings
S * mkS(int n, char ** args) {
S * head = NULL;
if (n > 0 && (head = calloc(n, sizeof(S)))){
S * curr = head - 1;
while (n-- > 0) {
curr++;
curr->val = *args++;
curr->next = curr + 1;
}
curr->next = NULL;
}
return head;
}
一种扭转名单的方法包括传回新的头部 列表一旦找到它。我们不需要本地(因为我们只是移动 当前元素到新的结束),但我们需要它以便调用者 我们完成后会有一个指向列表头部的指针。
// reverse a list one way
S * revS1( S * const head ){
if (head && head->next) {
S * const new_head = revS1( head->next );
head->next->next = head;
head->next = NULL;
return new_head;
} else {
return head;
}
}
另一种方法是指向指针。唯一的区别是 我们不需要返回任何东西,因为我们直接修改变量 来电者有。我更喜欢这种调用方法,因为它更清晰 我们正在修改列表,而不是返回副本。这也更难 因为调用者不小心地以这种方式松开了指向新头的指针。
// reverse a list another way
void revS2( S ** phead ){
S * const head = *phead;
if (head && head->next) {
*phead = head->next;
revS2( phead );
head->next->next = head;
head->next = NULL;
}
}
但是,比其中任何一个更好的是非递归地反转列表。 这些函数都不是尾递归的,因此编译器具有 为列表中的每个元素分配新的堆栈帧。试着扭转一下 足够的清单,你会打击你的堆栈。更好地反转清单 使用while循环。
// reverse a list non-recursively
void revS3( S ** phead ){
S * head = *phead;
S * reversed = NULL;
while (head) {
S * curr = head;
head = curr->next;
curr->next = reversed;
reversed = curr;
}
*phead = reversed;
}
现在我们可以通过在命令行中构建列表来测试我们的结果:
// just use the command line arguments as our list
int main(int argc, char** argv){
S* list1 = mkS(argc - 1, argv + 1);
S* list2 = mkS(argc - 1, argv + 1);
S* list3 = mkS(argc - 1, argv + 1);
showS( "given", list1 );
showS( "revS1", revS1(list1) );
revS2( &list2 );
showS( "revS2", list2 );
revS2( &list3 );
showS( "revS3", list3 );
return 0;
}
所以让我们编译:
% gcc -Wall linked_list.c -o linked_list
做一些测试
% ./linked_list
given: ()
revS1: ()
revS2: ()
revS3: ()
% ./linked_list first second third
given: ( first, second, third )
revS1: ( third, second, first )
revS2: ( third, second, first )
revS3: ( third, second, first )
% ./linked_list only
given: ( only )
revS1: ( only )
revS2: ( only )
revS3: ( only )