簡體   English   中英

C與雙向鏈表交換

[英]C swapping with doubly linked list

我試圖交換節點在鏈表中的位置,然后再使用排序功能進行排序。 這些功能中的任何一個出現邏輯錯誤。 當我運行程序時,它將進入無限循環。

更新的代碼

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


}

要處理節點與公共代碼相鄰或不相鄰的兩種情況,請先將(外部)指針交換到兩個節點,然后再交換兩個節點的(內部)指針。 如果節點相鄰,最終將根據需要旋轉指針,如果節點不相鄰,則交換成對的指針。 請注意,如果節點相鄰,則“外部”指針之一將是“其他”節點內部指針之一,反之亦然,但仍然可行:首先交換“外部”指針,然后交換“內部”指針。

進行交換時,請確保根據需要使用臨時指針(從技術上講是指向節點指針的指針),否則在交換操作過程中會部分覆蓋節點指針。 如果卡住了,我可以稍后再舉一個例子。

更新 -圖型為例,說明發生了什么,使用僅僅用下一個指針作為一個例子的單鏈表。 假設您從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->和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. 當要交換的節點相鄰時, swap功能不起作用,但是sort功能僅交換相鄰節點!
  2. 交換兩個節點ptr1ptr1->next_sort函數檢查被交換的第一個節點ptr1是否在列表的開頭,如果是,則使ptr1->next_成為列表的開頭。 但是,這兩個節點現在的順序相反,因此在這種情況下,應該使ptr1->prev_成為列表的開頭。
  3. 如果第一個自變量小於第二個自變量,比較函數通常返回負值;如果相等,則返回零;如果第一個自變量大於第二個自變量,則比較函數返回正值。 如果第一個參數小於或等於第二個參數, sort函數當前似乎期望比較函數返回0。 這可能是錯誤,也可能不是錯誤,但這是非常規的。

另外,可以簡化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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM