C 与双向链表交换



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

更新的代码

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("swappingn");
swap(&ptr1,&ptr1->next_);
if(ptr1==*recordsHead)
{
(*recordsHead)=ptr1->next_;
}
swapped=1;
}
else ptr1 = ptr1->next_;
}
lptr = ptr1;
;
}
while (swapped);

}

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

  1. 当被交换的节点相邻时,swap函数不起作用,但sort函数只交换相邻的节点!
  2. 在交换两个节点ptr1ptr1->next_后,sort函数检查被交换的第一个节点ptr1是否位于列表的头部,如果是,则ptr1->next_成为列表的头部。但是,这两个节点现在的顺序相反,因此在这种情况下,它应该使ptr1->prev_成为列表的头部。
  3. 比较函数通常在第一个参数小于第二个参数时返回负值,如果
  4. 它们相等,则返回零,如果第一个参数大于第二个参数,则返回正值。如果第一个参数小于或等于第二个参数,则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:%un", 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

若要处理节点与公共代码相邻或不相邻的两种情况,请先交换指向两个节点的(外部)指针,然后交换两个节点的(内部)指针。如果节点相邻,这将根据需要轮换指针,如果节点不相邻,这将交换指针对。请注意,如果节点相邻,则其中一个"外部"指针将是"其他"节点内部指针之一,反之亦然,但它仍然有效:首先交换"外部"指针,然后交换"内部"指针。

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

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

最新更新