简体   繁体   English

C与双向链表交换

[英]C swapping with doubly linked list

I'm trying to swap the position of nodes in a linked list and later on sorting with a sort function. 我试图交换节点在链表中的位置,然后再使用排序功能进行排序。 I'm getting a logical error in either one of these functions. 这些功能中的任何一个出现逻辑错误。 When I run the program it goes in infinite loop. 当我运行程序时,它将进入无限循环。

updated code 更新的代码

int adjuctNodes(struct student_record_node** n1, struct student_record_node** n2)

{
      struct student_record_node* prev_;
      struct student_record_node* next_;  
      return((*n1)->next_==(*n2) && (*n2)->prev_ == (*n1))||
      ( (*n1)->prev_ ==(*n2) && (*n2)->next_ == (*n1) );
}

void updateOuterPointer(struct student_record_node** n)

{
     struct student_record_node* next_;
     struct student_record_node* prev_;
     if((*n)->next_!=NULL)
             (*n)->prev_->next_=(*n);
     if((*n)->next_ !=NULL)
             (*n)->next_->prev_=(*n);
}


/*Swaping */

void swap(struct student_record_node** node1, struct student_record_node** node2)

{


          struct student_recod_node* prev_;
          struct student_recod_node* next_;
          struct student_record_node* ptr=(*node1)->next_;

             if(adjucntNodes((node1),(node2)))
     {
             (node1)->prev_=pnode2;
             (node2)->prev_=pnode0;
             (node1)->next_=pnode3;
             (node2)->next_=pnode1;

     }else{

             (node1)->prev_=pnode1;
             (node2)->prev_=pnode0;
             (node1)->next_=pnode3;
             (node2)->next_=pnode2;
     }

     updateOuterPointer((node1));
     updateOuterPointer((node2));

} 
 /*Sorting linked list*/


void sort(struct student_record_node**recordsHead,int(*compare_fcn)(struct  
student_record_node*,struct student_record_node*))

 {

         int swapped;
         struct student_record_node *ptr1=*recordsHead;
         struct student_record_node *lptr = NULL;

         if (ptr1 == NULL)
                 return;

         do
         {
                 swapped = 0;
                 ptr1 = *recordsHead;


                 while (ptr1->next_ != lptr)
                 {
                              if (compare_fcn(ptr1,ptr1->next_))
                         {
                                 printf("swapping\n");
                                swap(&ptr1,&ptr1->next_);
                                if(ptr1==*recordsHead)
                                 {
                                    (*recordsHead)=ptr1->next_;
                                 }
                                 swapped=1;

                         }

                         else ptr1 = ptr1->next_;
                 }
                    lptr = ptr1;
                         ;
         }
         while (swapped);


}

To handle both the cases where nodes are adjacent or not adjacent with common code, first swap the (external) pointers to the two nodes, then swap the two node's (internal) pointers. 要处理节点与公共代码相邻或不相邻的两种情况,请先将(外部)指针交换到两个节点,然后再交换两个节点的(内部)指针。 This will end up rotating the pointers as needed if the nodes are adjacent, and swapping pairs of pointers if the nodes are not adjacent. 如果节点相邻,最终将根据需要旋转指针,如果节点不相邻,则交换成对的指针。 Note if the nodes are adjacent, one of the "external" pointers will be one of the "other" nodes internal pointers, and vice versa, but it still works out: swap "external" pointers first, then "internal" pointers next. 请注意,如果节点相邻,则“外部”指针之一将是“其他”节点内部指针之一,反之亦然,但仍然可行:首先交换“外部”指针,然后交换“内部”指针。

Be sure to use temporary pointers (technically pointers to node pointers) as needed when doing the swaps, otherwise you overwrite node pointers part way through a swap operation. 进行交换时,请确保根据需要使用临时指针(从技术上讲是指向节点指针的指针),否则在交换操作过程中会部分覆盖节点指针。 If stuck, I can update with an example later. 如果卡住了,我可以稍后再举一个例子。

update - diagram type example to show what happens, using a single linked list with just next pointers as an example. 更新 -图型为例,说明发生了什么,使用仅仅用下一个指针作为一个例子的单链表。 Assume you start with 5 nodes, 0 to 4: 假设您从5到0到4个节点开始:

0->1->2->3->4

swap 1 and 3, 0-> and 2-> are the external pointers, 1-> and 3-> are internal. 交换1和3,0->和2->是外部指针,1->和3->是内部指针。 First swap 0-> and 2-> 第一次交换0->和2->

0->3
2->1

then swap 1-> and 3-> 然后交换1->和3->

1->4
3->2

resulting in 导致

0->3->2->1->4

Starting from 0->1->2->3->4 swap 1 and 2, 0-> and 1-> are external, 1-> and 2-> are internal. 从0-> 1-> 2-> 3-> 4交换1和2开始,0->和1->在外部,1->和2->在内部。 Swap 0-> and 1-> 交换0->和1->

0->2
1->1

then swap 1-> and 2-> 然后交换1->和2->

1->3
2->1

resulting in 导致

0->2->1->3->4

Example swap code. 交换代码示例。 This code assume that there is head pointer to point to the first node, and a tail pointer to point to the last node (or NULL). 此代码假定有指向第一个节点的头指针和指向最后一个节点的尾指针(或NULL)。

struct student_record_node *Head = &firstnode;  /* head */
struct student_record_node *Tail = &lastnode;   /* tail (NULL is ok) */

/* swap function */

void swap(struct student_record_node **Head,
          struct student_record_node **Tail,
          struct student_record_node *node1,
          struct student_record_node *node2)
{
struct student_record_node **en1 /* & external next ptr to 1 */
struct student_record_node **en2 /* & external next ptr to 2 */
struct student_record_node **ep1 /* & external prev ptr to 1 */
struct student_record_node **ep2 /* & external prev ptr to 2 */
struct student_record_node  *tmp /* temp node ptr */
    en1 = (node1->prev_ != NULL) ? &(node1->prev_->next_) : Head;
    en2 = (node2->prev_ != NULL) ? &(node2->prev_->next_) : Head;
    ep1 = (node1->next_ != NULL) ? &(node1->next_->prev_) : Tail;
    ep2 = (node2->next_ != NULL) ? &(node2->next_->prev_) : Tail;
    /* swap en1, en2 */
    tmp = *en1;
    *en1 = *en2;
    *en2 = tmp;
    /* swap ep1, ep2 */
    tmp = *ep1;
    *ep1 = *ep2;
    *ep2 = tmp;
    /* swap n1, n2 next_ */
    tmp = node1->next_;
    node1->next_ = node2->next_;
    node2->next_ = tmp;
    /* swap n1, n2 prev_ */
    tmp = node1->prev_;
    node1->prev_ = node2->prev_;
    node2->prev_ = tmp;
}

    /* call to swap function */
    swap(&Head, &Tail, node1, node2);

There are two main problems in the original code, and possibly a third: 原始代码中有两个主要问题,可能还有第三个问题:

  1. The swap function does not work when the nodes being swapped are adjacent, but the sort function only swaps adjacent nodes! 当要交换的节点相邻时, swap功能不起作用,但是sort功能仅交换相邻节点!
  2. After swapping two nodes ptr1 and ptr1->next_ , the sort function checks if the first node being swapped, ptr1 , was at the head of the list, and if so makes ptr1->next_ the head of the list. 交换两个节点ptr1ptr1->next_sort函数检查被交换的第一个节点ptr1是否在列表的开头,如果是,则使ptr1->next_成为列表的开头。 However, the two nodes are now in reverse order, so it should make ptr1->prev_ the head of the list in this case. 但是,这两个节点现在的顺序相反,因此在这种情况下,应该使ptr1->prev_成为列表的开头。
  3. Comparison functions usually return a negative value if the first argument is less than the second argument, zero if they are equal, or a positive value if the first argument is greater than the second argument. 如果第一个自变量小于第二个自变量,比较函数通常返回负值;如果相等,则返回零;如果第一个自变量大于第二个自变量,则比较函数返回正值。 The sort function currently seems to expect the comparison function to return 0 if the first argument is less than or equal to the second argument. 如果第一个参数小于或等于第二个参数, sort函数当前似乎期望比较函数返回0。 This may or may not be a bug, but it is unconventional. 这可能是错误,也可能不是错误,但这是非常规的。

Additionally, the interface to the swap function can be simplified as there is no need to pass pointers to pointers to the nodes. 另外,可以简化swap功能的接口,因为不需要将指针传递给指向节点的指针。

The following example program fixes the above problems: 以下示例程序解决了上述问题:

#include <stdio.h>
#include <string.h>

struct student_record_node {
    struct student_record_node *next_;
    struct student_record_node *prev_;
    const char *name;
    unsigned int age;
};

void swap(struct student_record_node *node1, struct student_record_node *node2)
{
    struct student_record_node *ptr1, *ptr2;

    /* Swap the 'next_' pointers, taking adjacency into account. */
    ptr1 = node1 == node2->next_ ? node2 : node2->next_;
    ptr2 = node2 == node1->next_ ? node1 : node1->next_;
    node1->next_ = ptr1;
    node2->next_ = ptr2;
    /* Swap the 'prev_' pointers, taking adjacency into account. */
    ptr1 = node1 == node2->prev_ ? node2 : node2->prev_;
    ptr2 = node2 == node1->prev_ ? node1 : node1->prev_;
    node1->prev_ = ptr1;
    node2->prev_ = ptr2;
    /* Fix the links from other nodes. */
    if (node1->next_) node1->next_->prev_ = node1;
    if (node1->prev_) node1->prev_->next_ = node1;
    if (node2->next_) node2->next_->prev_ = node2;
    if (node2->prev_) node2->prev_->next_ = node2;
}

int compare_ages(const struct student_record_node *a,
        const struct student_record_node *b)
{
    return a->age < b->age ? -1 : a->age > b->age ? 1 : 0;
}

int compare_names(const struct student_record_node *a,
        const struct student_record_node *b)
{
    return strcmp(a->name, b->name);
}

void sort(struct student_record_node **recordsHead,
        int(*compare_fcn)(const struct student_record_node *,
                const struct student_record_node *))
{
    int swapped;
    struct student_record_node *ptr1;
    struct student_record_node *lptr = NULL;

    if (*recordsHead == NULL)
        return;

    do
    {
        swapped = 0;
        ptr1 = *recordsHead;

        while (ptr1->next_ != lptr)
        {
            if (compare_fcn(ptr1, ptr1->next_) > 0)
            {
                printf("swapping (%s:%u <=> %s:%u)\n", ptr1->name, ptr1->age,
                        ptr1->next_->name, ptr1->next_->age);
                swap(ptr1, ptr1->next_);
                if (ptr1 == *recordsHead)
                {
                    /* ptr1 is now the second node. */
                    (*recordsHead) = ptr1->prev_;
                }
                swapped = 1;
            }
            else
            {
                ptr1 = ptr1->next_;
            }
        }
        lptr = ptr1;
    }
    while (swapped);
}

void dump(const struct student_record_node *students)
{
    const struct student_record_node *prev_ = NULL;
    unsigned int pos = 0;

    while (students)
    {
        if (students->prev_ != prev_)
        {
            printf("[%u] ** Bad prev_ link!\n", pos);
        }
        printf("[%u] %s:%u\n", pos, students->name, students->age);
        pos++;
        prev_ = students;
        students = students->next_;
    }
}

int main(void)
{
    static struct student_record_node testdata[] =
    {
        { testdata + 1, NULL, "susan", 20 },
        { testdata + 2, testdata + 0, "bill", 21 },
        { testdata + 3, testdata + 1, "joe", 18 },
        { testdata + 4, testdata + 2, "tom", 19 },
        { NULL, testdata + 3, "karen", 21 },
    };
    struct student_record_node *students = testdata;

    puts("Original order:");
    dump(students);
    puts("By name:");
    sort(&students, compare_names);
    dump(students);
    puts("By age:");
    sort(&students, compare_ages);
    dump(students);
    return 0;
}

Output: 输出:

Original order:
[0] susan:20
[1] bill:21
[2] joe:18
[3] tom:19
[4] karen:21
By name:
swapping (susan:20 <=> bill:21)
swapping (susan:20 <=> joe:18)
swapping (tom:19 <=> karen:21)
swapping (susan:20 <=> karen:21)
[0] bill:21
[1] joe:18
[2] karen:21
[3] susan:20
[4] tom:19
By age:
swapping (bill:21 <=> joe:18)
swapping (karen:21 <=> susan:20)
swapping (karen:21 <=> tom:19)
swapping (bill:21 <=> susan:20)
swapping (bill:21 <=> tom:19)
swapping (susan:20 <=> tom:19)
[0] joe:18
[1] tom:19
[2] susan:20
[3] bill:21
[4] karen:21

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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