[英]Swapping linked list items issue C
我正在尝试将以下列表中的“信息”字段反转
struct nodo {
int info;
struct nodo *next;
struct nodo *prev;
} ;
typedef struct nodo nodo;
这是主要的,这两个输出应该是n个成员的原始列表和倒排的列表(第一个值转到n,第二个值n-1,依此类推)
int main(int argc, const char * argv[]) {
struct nodo *p;
p = CreateList();
PrintList(p);
IvertList(p);
Printlist(p);
return 0;
}
这是InvertList():(Count()函数只是返回列表的维数,我知道这是一种凌乱的方式,但是我现在只关注结果)
void InvertList (struct nodo *p) {
int tmp = 0, num = 0, i = 0;
num = (Count(p));
tmp = num;
for (i=1; i!=tmp; i++) {
Swap(p,num);
num--;
}
}
这是Swap(),这应该将值(int info)带到列表的第一位,最后一次与每个交换:
void Swap (struct nodo *p, int n) {
int *tmp1 = NULL, *tmp2 = NULL;
int i;
for ( i = 1; i != n && p != NULL; i++) {
tmp1 = &p->info;
p = p->succ;
tmp2 = &p->info;
p->info = *tmp1;
p->prec->info = *tmp2;
}
}
现在我得到的输出是:
Value: 1
Value: 2
Value: 3
Value: 4
Value: 5
Value: 1
Value: 1
Value: 1
Value: 1
Value: 1
最后5个值应为5-4-3-2-1。
代码中的错误无法抵御,您根本不会颠倒物理列表,我可以保证,但是保证是最重要的。
链表的倒置意味着所有指针都切换方向,旧尾变成新头。 您似乎在避免这种情况,而是尝试交换节点信息值。
要使用简单的指针交换来反转列表,请执行以下操作:
// note head pointer passed by address
void InvertList(node **pp)
{
node *cur = *pp;
while (cur)
{
node *tmp = cur->prev;
cur->prev = cur->next;
cur->next = tmp;
*pp = cur;
cur = cur->prev;
}
}
并从main()
调用为:
InvertList(&p);
请注意, 不需要交换,复制等信息值。节点指针只需切换方向,其枚举将从另一端开始。 完整的工作示例如下所示:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int info;
struct node *next;
struct node *prev;
};
typedef struct node node;
static void PrintList(const node *head)
{
while (head)
{
printf("%d: this=%p, prev=%p, next=%p\n",
head->info, head, head->prev, head->next);
head = head->next;
}
}
static void InvertList(node **pp)
{
node *cur = *pp;
while (cur)
{
node *tmp = cur->prev;
cur->prev = cur->next;
cur->next = tmp;
*pp = cur;
cur = cur->prev;
}
}
int main()
{
node *prev = NULL, *head = NULL, **pp = &head;
for (int i=1; i<=5; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->info = i;
(*pp)->prev = prev;
prev = *pp;
pp = &(*pp)->next;
}
*pp = NULL;
PrintList(head); // prints 1,2,3,4,5
InvertList(&head);
PrintList(head); // prints 5,4,3,2,1
}
输出 (地址明显不同)
1: this=0x1001054b0, prev=0x0, next=0x1001054d0
2: this=0x1001054d0, prev=0x1001054b0, next=0x1001054f0
3: this=0x1001054f0, prev=0x1001054d0, next=0x100105510
4: this=0x100105510, prev=0x1001054f0, next=0x100105530
5: this=0x100105530, prev=0x100105510, next=0x0
5: this=0x100105530, prev=0x0, next=0x100105510
4: this=0x100105510, prev=0x100105530, next=0x1001054f0
3: this=0x1001054f0, prev=0x100105510, next=0x1001054d0
2: this=0x1001054d0, prev=0x1001054f0, next=0x1001054b0
1: this=0x1001054b0, prev=0x1001054d0, next=0x0
Swap
fcn中有一个错误:
p->info = *tmp1;
p->prev->info = *tmp2;
但是,那时的tmp1
和tmp2
是什么? 好吧,在我们推进p
, tmp1
指向p->prev->info
,而tmp2 = &p->info;
因此,我们可以将这些分配实际上重写为:
p->info = p->prev->info;
p->prev->info = p->info;
因此,实际上我们可以再次将它们重写为:
p->info = p->prev->info;
p->prev->info = p->prev->info;
因此,第二个分配不会改变任何有效的内容。 因此,对InvertList
中的Swap
的第一次调用将采用第一个元素(1)的值,并将列表中的所有值都设置为等于它。 随后调用Swap
行为类似,但没有效果,因为列表已包含全1。
这是重写Swap
的简单方法:
void Swap(struct nodo *p, int n)
{
if (n <= 1)
return;
int tmp = p->info;
for (int i = 1; i != n; ++i, p = p->next)
p->info = p->next->info;
p->info = tmp;
}
但是请注意,您编写InvertList
的方式是执行theta(n ^ 2)的工作。 第一次循环迭代将第一个元素n-1个点移位,第二次迭代将第一个元素n-2个点移位,第三次迭代将第一个元素n-3个点移位,依此类推,向下移动第一个元素1个点。 因此,您最终要做类似n *(n-1)/ 2的总移位来反转列表。
链表可以在theta(n)工作中反转/反转。 看看您是否可以找到一种更好的方法来执行此操作。 如果您有一个指向列表的开头和结尾的指针(无论如何,您通常都希望这样),那么您可以执行类似于反转字符串中字符的操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.