C与双向链表交换

时间:2016-11-23 13:40:02

标签: c sorting swap doubly-linked-list

我试图交换链表中节点的位置 然后使用sort函数进行排序。我在其中一个函数中遇到逻辑错误。当我运行程序时,它会进入无限循环。

更新代码

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);


}

2 个答案:

答案 0 :(得分:1)

要处理节点与公共代码相邻或不相邻的情况,首先将(外部)指针交换到两个节点,然后交换两个节点的(内部)指针。如果节点是相邻的,这将最终根据需要旋转指针,并且如果节点不相邻则交换指针对。注意节点是否相邻,其中一个是"外部"指针将成为"其他"节点内部指针,反之亦然,但它仍然有效:swap" external"指针首先,然后"内部"指针下一步。

确保在执行交换时根据需要使用临时指针(技术上指向节点指针的指针),否则在交换操作的一部分中覆盖节点指针。如果卡住,我可以稍后用一个例子更新。

update - 图表类型示例以显示发生的情况,使用单个链接列表仅使用下一个指针作为示例。假设您从5个节点开始,0到4:

0->1->2->3->4
交换1和3,0->和2->是外部指针,1->和3->是内部的。首先交换0->和2->

0->3
2->1

然后交换1->和3->

1->4
3->2

导致

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

从0-> 1-> 2-> 3-> 4交换1和2,0-> 0开始。并且1->是外部的,1->和2->是内部的。交换0->和1->

0->2
1->1

然后交换1->和2->

1->3
2->1

导致

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

示例交换代码。此代码假定有指向第一个节点的头指针,以及指向最后一个节点(或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);

答案 1 :(得分:1)

原始代码中存在两个主要问题,可能还有第三个问题:

  1. 当被交换的节点相邻时,swap函数不起作用,但sort函数只交换相邻节点!
  2. 交换两个节点ptr1ptr1->next_后,sort函数检查交换的第一个节点ptr1是否位于列表的头部,如果所以使ptr1->next_成为列表的头部。但是,这两个节点现在的顺序相反,所以在这种情况下它应该使ptr1->prev_成为列表的头部。
  3. 如果第一个参数小于第二个参数,则比较函数通常返回负值,如果它们相等则返回零,如果第一个参数大于第二个参数,则返回正值。如果第一个参数小于或等于第二个参数,sort函数当前似乎期望比较函数返回0。这可能是也可能不是错误,但它是非常规的。
  4. 此外,可以简化swap函数的接口,因为不需要将指针传递给指向节点的指针。

    以下示例程序修复了上述问题:

    #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;
    }
    

    输出:

    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