繁体   English   中英

交换链接列表项目问题C

[英]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;

但是,那时的tmp1tmp2是什么? 好吧,在我们推进ptmp1指向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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM