【问题标题】:Swap Position of the Node in C在 C 中交换节点的位置
【发布时间】:2017-09-21 20:20:44
【问题描述】:

好的,所以我想交换两个节点的 POSITION(不是值)。
我的程序运行时出现任何错误或警告,但我不确定我是否正在交换位置或值。
这是我的排序功能:

void sort(struct node **recordsHead,int (*compare_fcn)(struct node*, struct node*)) 
{   
 void swap(struct node**, struct node**);   
 struct node *tmp,*lastPtr = NULL;  
 int swapped;
  do {
      swapped = 0;
      tmp = *recordsHead;

      while (tmp->next_ != lastPtr)
      {
          if (compare_fcn(tmp, tmp->next_))
          {
              swap(&tmp, &(tmp->next_));
              swapped = 1;
          }
          tmp = tmp->next_;
      }
            lastPtr = tmp;
      } while (swapped);

}


这是我的交换函数

void swap(struct node** node1, struct node** node2)
{
  student_record *tmp;

  tmp = (*node1)->record_;
  (*node1)->record_ = (*node2)->record_;
  (*node2)->record_ = tmp;
}

谢谢。

【问题讨论】:

  • 嗯,你的sort 有一个明显的洞。您可以不按特定顺序交换指针。如果tmp > tmp->next,你交换。如果tmp < tmp->next 你做了 same 的事情导致既没有 ascending 也没有 descending 交换,只是交换?这可能是您的意图,但您通常需要if (compare_fcn (tmp, tmp->next) > 0)< 0,分别用于升序和降序排序。有关指针交换问题,请参阅 @dbush 答案。
  • 由于你的节点是链表中的节点,如果你交换第一个节点,你必须重新分配head(否则它将不再指向链表的开头),另外,每次交换时都必须重新连接 ->next 地址以指向正确的节点(如果交换最后一个节点,则为 NULL),否则 ->next 将不再指向列表中正确的 ->next 节点。

标签: c sorting linked-list nodes bubble-sort


【解决方案1】:

Rachel,从 cmets 继续,因为您似乎试图在 linked-list 中“交换指针”,所以您不能简单地交换列表中的相邻指针而不破坏节点(例如,node->next 指针将不再指向列表中的 next 节点)。考虑以下几点:

+------+      +------+      +------+     
|  a   |  +-->|  b   |  +-->|  c   |  +--> ...
+------+  |   +------+  |   +------+  |
| next |--+   | next |--+   | next |--+   
+------+      +------+      +------+      

在哪里

a->next = b;
b->next = c;
c->next ...

如果你只是交换ab指针,a->nextb-next指向哪里?例如

+------+      +------+      +------+     
|  b   |  +-->|  a   |  +-->|  c   |  +--> ...
+------+  |   +------+  |   +------+  |
| next |--+   | next |--+   | next |--+   
+------+      +------+      +------+      

由于您没有交换(或重新连接)next 指针,它们仍然保存(指向)原始内存位置,例如a->next = b;b->next = c; (这是不对的,你会完全跳过'a',如果你确实点击了aa->next 会备份到b,然后b->next 会跳到c .. .)

所以如果你想按一些成员值排序而不是交换值,而是交换指针,你必须“re-wire”每个next指针指向与下一个节点以正确的排序顺序升序(或降序)成员值,这不同于简单地交换 abc 指针值。

接下来,您必须考虑两种不同的情况。重新连接 first 节点,从而更改列表本身的地址(例如 head 指针),然后是所有其他节点的一般情况(对于 单链接-list、循环列表和双向链表需要额外注意prevlast->first 链接)。您需要可视化和考虑的两种情况是涉及第一个节点的交换:

         head                  next                next->next
        (iter)              (iter->next)       (iter->next->next)
     +------------+        +------------+        +------------+
     |   Payload  |        |   Payload  |        |   Payload  |
     +------------+        +------------+        +------------+
     |   Next     |------->|   Next     |------->|   Next     |--->+
     +------------+        +------------+        +------------+

和你的一般情况:

         prev                 current                next
        (last)                 iter               (iter->next)
     +------------+        +------------+        +------------+
     |   Payload  |        |   Payload  |        |   Payload  |
     +------------+        +------------+        +------------+
     |   Next     |------->|   Next     |------->|   Next     |--->+
     +------------+        +------------+        +------------+

对于涉及head 节点的情况(并使用struct node *iter = *head; 并选择tmp = iter->next; 进行替换,您可以执行以下操作:

            if (iter == *head) {
                struct node *tmp = iter->next;
                iter->next = tmp->next;
                tmp->next = iter;
                *head = tmp;
                iter = *head;
            }

要处理一般情况(在以下else 子句中,您可以执行以下操作:

            else {
                struct node *tmp = iter->next;
                iter->next = tmp->next;
                tmp->next = last->next;
                last->next = tmp;
                iter = tmp;
            }
            swapped = 1;

您将在您的代码中完全不使用 swap 函数(您可以,但您需要传递列表地址,以便与 head 进行比较。

在一个简短的示例中将所有部分放在一起,并按每个节点内的整数值升序排序,您可以执行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAXN 10

typedef struct node {
    int val;
    struct node *next;
} node;

int cmp (struct node *a, struct node *b) {
    /* (a > b) - (a < b) */
    return (a->val > b->val) - (a->val < b->val);
}

void sort (struct node **recordsHead, 
            int (*compare_fcn)(struct node*, struct node*));

int main (void) {

    srand (time (NULL));

    node *head = NULL;

    for (int i = 0; i < MAXN; i++) 
    {
        node *newnode = malloc (sizeof *newnode);
        if (!newnode) { /* allocate node and validate memory */
            fprintf (stderr, "error: memory exhausted node '%d'.\n", i);
            break;
        }

        newnode->val = rand() % 100;    /* initialize pointers */
        newnode->next = NULL;

        if (!head)          /* new list, assign to head */
            head = newnode;
        else {              /* otherwise iterate and add to end */
            node *iter = head;
            for (; iter->next; iter = iter->next) {}
            iter->next = newnode;
        }
    }

    int j = 0;  /* output list (including pointer addresses) */
    printf ("\noriginal pointer and value order:\n\n");
    for (node *iter = head; iter; iter = iter->next)
        printf ("node[%3d] : %3d,       addr: %p, next: %p\n",
                j++, iter->val, (void*)iter, (void*)iter->next);

    sort (&head, cmp);  /* sort by swapping pointers */

    j = 0;      /* output sorted list (with addresses */
    printf ("\nsorted pointer and value order:\n\n");
    for (node *iter = head; iter; iter = iter->next)
        printf ("node[%3d] : %3d,       addr: %p, next: %p\n",
                j++, iter->val, (void*)iter, (void*)iter->next);

    /* free list memory */
    node *victim = NULL;    /* node to delete */
    for (node *iter = head; iter; iter = iter->next) {
        if (victim)     /* cannot delete until after loop increment */
            free (victim);
        victim = iter;  /* so save node as victim, delete next iteration */
    }
    if (victim)         /* free last node */
        free (victim);

    return 0;
}

/* sort (ascending) by rewiring nodes */
void sort (struct node **head, int (*compare_fcn)(struct node*, struct node*)) 
{   
    struct node *iter, *last = NULL;  
    int swapped;

    do {    /* while a swap occurs during iterating list */
        swapped = 0;
        iter = *head;

        while (iter->next != NULL)  /* traverse each node in list */
        {
            if (compare_fcn (iter, iter->next) > 0) /* sort ascending */
            {
                if (iter == *head) {    /* swap head pointers (rewire) */
                    struct node *tmp = iter->next;
                    iter->next = tmp->next;
                    tmp->next = iter;
                    *head = tmp;
                    iter = *head;
                }
                else {  /* swap of remaining nondes (rewire pointers) */
                    struct node *tmp = iter->next;
                    iter->next = tmp->next;
                    tmp->next = last->next;
                    last->next = tmp;
                    iter = tmp;
                }
                swapped = 1;    /* swap flag */
            }
            last = iter;        /* update last */
            iter = iter->next;  /* advance ptr */
        }
    } while (swapped);
}

使用/输出示例

$ ./bin/llminsort

original pointer and value order:

node[  0] :  63,       addr: 0x9fb010, next: 0x9fb030
node[  1] :  76,       addr: 0x9fb030, next: 0x9fb050
node[  2] :   4,       addr: 0x9fb050, next: 0x9fb070
node[  3] :  95,       addr: 0x9fb070, next: 0x9fb090
node[  4] :  76,       addr: 0x9fb090, next: 0x9fb0b0
node[  5] :  64,       addr: 0x9fb0b0, next: 0x9fb0d0
node[  6] :  81,       addr: 0x9fb0d0, next: 0x9fb0f0
node[  7] :  43,       addr: 0x9fb0f0, next: 0x9fb110
node[  8] :  51,       addr: 0x9fb110, next: 0x9fb130
node[  9] :  68,       addr: 0x9fb130, next: (nil)

sorted pointer and value order:

node[  0] :   4,       addr: 0x9fb050, next: 0x9fb0f0
node[  1] :  43,       addr: 0x9fb0f0, next: 0x9fb110
node[  2] :  51,       addr: 0x9fb110, next: 0x9fb010
node[  3] :  63,       addr: 0x9fb010, next: 0x9fb0b0
node[  4] :  64,       addr: 0x9fb0b0, next: 0x9fb130
node[  5] :  68,       addr: 0x9fb130, next: 0x9fb030
node[  6] :  76,       addr: 0x9fb030, next: 0x9fb090
node[  7] :  76,       addr: 0x9fb090, next: 0x9fb0d0
node[  8] :  81,       addr: 0x9fb0d0, next: 0x9fb070
node[  9] :  95,       addr: 0x9fb070, next: (nil)

内存泄漏/错误检查

您必须使用内存错误检查程序来确保您不会尝试写入超出/超出分配的内存块的范围,尝试读取或基于未初始化的值进行条件跳转,最后,确认您释放了所有已分配的内存。

对于 Linux,valgrind 是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。

$ valgrind ./bin/llminsort
==1844== Memcheck, a memory error detector
==1844== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1844== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==1844== Command: ./bin/llminsort
==1844==

original pointer and value order:

node[  0] :  27,       addr: 0x51d8040, next: 0x51d8090
node[  1] :  68,       addr: 0x51d8090, next: 0x51d80e0
node[  2] :  55,       addr: 0x51d80e0, next: 0x51d8130
node[  3] :  44,       addr: 0x51d8130, next: 0x51d8180
node[  4] :  47,       addr: 0x51d8180, next: 0x51d81d0
node[  5] :  10,       addr: 0x51d81d0, next: 0x51d8220
node[  6] :   8,       addr: 0x51d8220, next: 0x51d8270
node[  7] :  13,       addr: 0x51d8270, next: 0x51d82c0
node[  8] :  73,       addr: 0x51d82c0, next: 0x51d8310
node[  9] :  11,       addr: 0x51d8310, next: (nil)

sorted pointer and value order:

node[  0] :   8,       addr: 0x51d8220, next: 0x51d81d0
node[  1] :  10,       addr: 0x51d81d0, next: 0x51d8310
node[  2] :  11,       addr: 0x51d8310, next: 0x51d8270
node[  3] :  13,       addr: 0x51d8270, next: 0x51d8040
node[  4] :  27,       addr: 0x51d8040, next: 0x51d8130
node[  5] :  44,       addr: 0x51d8130, next: 0x51d8180
node[  6] :  47,       addr: 0x51d8180, next: 0x51d80e0
node[  7] :  55,       addr: 0x51d80e0, next: 0x51d8090
node[  8] :  68,       addr: 0x51d8090, next: 0x51d82c0
node[  9] :  73,       addr: 0x51d82c0, next: (nil)
==1844==
==1844== HEAP SUMMARY:
==1844==     in use at exit: 0 bytes in 0 blocks
==1844==   total heap usage: 10 allocs, 10 frees, 160 bytes allocated
==1844==
==1844== All heap blocks were freed -- no leaks are possible
==1844==
==1844== For counts of detected and suppressed errors, rerun with: -v
==1844== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放已分配的所有内存并且没有内存错误。

查看一下,如果您有任何其他问题,请告诉我。

【讨论】:

    猜你喜欢
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多