交换节点在C中的位置

时间:2017-04-25 01:33:24

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

好的,我想交换两个节点的 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;
}

谢谢。

1 个答案:

答案 0 :(得分:0)

Rachel,继续发表评论,因为你似乎试图在链接列表中'交换指针',你不能简单地交换列表中的相邻指针而不破坏之间的联系。节点(例如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 ...)

因此,如果您希望按某些成员值排序而不是交换值,而是交换指针,则必须“重新连接”每个next指针以指向具有该节点的节点正确排序顺序中的下一个升序(或降序)成员值,与简单地交换abc指针值不同。

接下来,您必须考虑两个不同的案例。重新连接第一个节点,从而更改列表本身的地址(例如head指针),然后是所有其他节点的一般情况(单个) -linked-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)

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

仔细看看,如果您有任何其他问题,请告诉我。