【问题标题】:Sorted insertion in a linked list链表中的排序插入
【发布时间】:2017-10-19 22:35:43
【问题描述】:

我正在尝试在链表中编写一些基本函数,其中一个是排序插入。我明白它应该做什么,但它给了我一个半排序的列表。我不知道问题出在哪里。它可以完成工作,但有些数字不在正确的位置。因此,如果您能找到发生这种情况的确切位置,我将不胜感激。

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

struct node {
  int data;
  struct node* next;
};

struct node* sorted_insert(struct node* ptr, int data){
  struct node* newNode = malloc(sizeof(struct node));
  if (!newNode){
    printf("something went wrong using malloc");
  }
  newNode -> data = data;

  if(ptr->next == NULL) {
    newNode -> next = ptr; //ptr is the most recent element
    return newNode;
  } else {

    struct node* prev = ptr->next;
    struct node* current = ptr;

    if(prev->next == NULL){
      if((current -> data) < (newNode -> data)){
        newNode -> next = ptr;
        return newNode;
      } else {
        newNode -> next = ptr->next;
        ptr -> next = newNode;
        return ptr;
      }
    } else {

      while((current -> data) > data && (prev -> data) > data) {
        current = prev;
        prev = prev->next;
      }

      newNode -> next = prev;
      current -> next = newNode;
      return ptr;
    }

  }
}

struct node* insert(struct node* ptr, int data){
  struct node* newNode = malloc(sizeof(struct node));
  if (!newNode){
    printf("something went wrong using malloc");
  }
  newNode -> data = data;
  newNode -> next = ptr;
  return newNode;
}

void print(struct node* root){
  struct node* trav = root;
  while(trav->next != NULL){
    printf("%d\n", trav -> data);
    trav = trav -> next;
  }
}
int main(){
  struct node *head = NULL;
  head = malloc(sizeof(struct node));
  if (!head){
    printf("something went wrong using malloc");
  }

  head -> data = -1;
  head -> next = NULL;

  int i;
  srand(time(NULL));
  for(i = 0; i < 20; i++) {
    head = sorted_insert(head, rand()%2000);
     print(head);
     printf("\n");
  }

  //printf("number of elements %d\n", length(head));
  //print(head);
}

sorted_insert函数

样本输出:

1279
1755
1295
1983
1353
1313
1924
1635
1296
1807
1263
1257
1199
771
386
359
278
231
141
45

【问题讨论】:

  • 正如@klutt 所说。拆分问题,然后单独调试每个部分。测试 find_place() ,每端都有值,最后,比结尾少一个,在中间某处。使用一个空列表进行测试,一个具有一个值的列表,一个具有两个值的三个。在 find_place() 通过这些测试之前,不要尝试插入任何东西。通过 DEBUGGING 让它通过,使用你的调试器,或者至少使用许多额外的 printf 语句来检查正在发生的事情,从而修复一些东西并使测试通过。这就是软件开发的本质:编写代码(容易)、测试(不容易)和调试(困难)。冲洗/重复。
  • 修正像this

标签: c linked-list


【解决方案1】:

您的排序插入比它需要的要复杂一些。由于您最后使用的是虚拟节点,因此您只有 2 个条件要测试(如果您考虑将第 1 个节点添加为条件,则为 3 个)。

  1. newNode-&gt;data 是否大于 ptr-&gt;data?”如果是这样,只需将其添加到列表的前面并返回newNode

  2. 否则,只需遍历列表设置current=current-&gt;next 直到newNode-&gt;data &lt; current-&gt;next-&gt;data。然后在那个时候添加newNode

简化并清除您对 prevcurrent 指针约定的混淆选择,您可以将排序插入简化为以下内容:

struct node *sorted_insert (struct node *ptr, int data)
{
    struct node *current = ptr;
    struct node *newNode = malloc (sizeof (struct node));

    if (!newNode) {
        printf ("something went wrong using malloc");
    }
    newNode->data = data;
    newNode->next = NULL;       /* always initialize next ptr */

    /* first node, or newNode->data greates - add at front */
    if (current->next == NULL || newNode->data > current->data) {
        newNode->next = current;
        return newNode;
    }

    /* traverse list to sorted insertion point */
    while (current->next && newNode->data < current->next->data)
        current = current->next;

    newNode->next = current->next;
    current->next = newNode;

    return ptr;
}

更令人困惑的问题是,您在插入值时打印列表,而不是打印完整列表的内容。 (你可能会这样做是为了调试,如果是这样忽略......)。为了纠正这个问题——使用你的print函数,因为它被设计用来打印完整的列表(除了你最后的虚拟节点),例如

srand (time (NULL));
for (i = 0; i < 20; i++)
    head = sorted_insert (head, rand () % 2000);

print (head);

最后的两个附注:

  1. 不要printf 单个字符,这就是putchar 的用途,例如putchar ('\n');.

  2. main 的正确声明是 int 类型,因此它应该返回一个值(注意:如果您未能包含 return 语句,则会返回 0)请参阅:C11 Standard §5.1.2.2.1 Program startup (draft n1570)。另见:What should main() return in C and C++?

最后,与其将node-&gt;data 打印到stdout 以验证您的节点是否按排序顺序插入,不如养成编写和使用简短验证例程的习惯,这些例程只需检查顺序并只会抱怨(在某些情况下)有意义的方式)如果发现有问题。您可以使用print 函数的变体来比较previous-&gt;data &gt; current-&gt;data,并且仅在遇到错误时提供输出,例如

/* silently validate sort order, output to stderr 
 * only if unsorted nodes found. return 1 on error,
 * 0 otherwise.
 */
int chkorder (struct node *root)
{
    struct node *trav = root;
    int prev = trav->data;

    for (trav = trav->next; trav->next; trav = trav->next) {
        if (prev < trav->data) {
            fprintf (stderr, "error: unsorted nodes (%d < %d)\n",
                    prev, trav->data);
            return 1;
        }
        prev = trav->data;
    }
    return 0;
}

当然,通过转储到屏幕来检查 20 个值是可以的,但是以这种方式检查 20,000 则有点问题。然后,您可以使用以下内容验证您的插入:

if (chkorder (head))
    fprintf (stderr, "error: sorted_insert failure.\n");
else
    printf ("all nodes inserted in descending sort order.\n");

【讨论】:

  • 我在想头节点应该在列表的前面,只有 head->next 应该改变。 Head 可能是一个本地结构而不是被分配: |结构节点头 = {-1, NULL}; | sorted_insert(&head, ...); | .由于虚拟节点位于列表的头部,因此 sorted_insert 无需返回指针,因为它将改为更新 head->next(如果需要)。
  • 你和我。但是他使用虚拟节点的方式将其推到最后,然后在print 中迭代while(trav-&gt;next != NULL) 以防止打印最终节点。我不是特别喜欢这样做的方式,但这不是一种无效的方式。 (如果我有偏好,所有列表都是循环的,允许从任意点遍历到任意点,消除所有虚拟节点)
  • 常规列表也不需要虚拟节点,只需一个指向第一个节点的指针,还可以选择指向最后一个节点的指针以进行快速追加。在函数中,指向指针的指针可用于通过消除对前一个节点指针的特殊情况来简化代码: |节点**ppnode; |提前:| ppnode = &((*ppnode)->next); |.
  • 同意。对于循环列表,第一个节点也是数据节点——不需要像 headtail 这样的单独指针。一个节点是一个节点是一个节点。接线有点复杂,但您可以从一开始就从 a 迭代到 a-1 而不会出现问题。
  • 对于循环列表,您仍然需要指向列表的指针,通常是尾指针,因为可以使用 head = tail->next 生成本地头指针。
【解决方案2】:

代码正在使用虚拟头节点。通常虚拟节点在列表之前,而不是用于终止列表。代码不应在主程序中更改 head,并且 sorted_insert 不需要返回指向节点的指针,因为它更新 head->next,这是指向第一个节点的实际指针。 sorted_insert 应该设置 prev = ptr 和 current = ptr->next。要插入的检查应该是 newNode->data data (如果是这样,则在 current 之前插入 newNode)。无需设置 head->data = -1。不知道还有没有其他问题。

示例代码。节点更改为 typedef。虚拟节点在列表之前。 head 在函数中用作本地指针。添加了对 head == NULL 的检查。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct node_ {
    struct node_ * next;
    int data;
}node;

void sorted_insert(node * head, int data)
{
node * newNode;
node * curr;
    if(head == NULL)
        return;
    newNode = malloc(sizeof(node));
    if (!newNode){
        printf("something went wrong using malloc");
        return;
    }
    /* insert node, head used as previous ptr */
    newNode->data = data;
    curr = head->next;
    while(curr != NULL && curr->data <= data){
        head = curr;
        curr = curr->next;
    }
    head->next = newNode;
    newNode->next = curr;
}

void insert(node * head, int data)
{
    node * newNode;
    if(head == NULL)
        return;
    newNode = malloc(sizeof(node));
    if (!newNode){
        printf("something went wrong using malloc");
        return;
    }
    newNode->data = data;
    newNode->next = head->next;
    head->next = newNode;
}

void print(node * head)
{
    if(head == NULL)
        return;
    head = head->next;
    while(head != NULL){
        printf("%d\n", head -> data);
        head = head->next;
    }
}

void delete(node *head)
{
node * curr;
    if(head == NULL)
        return;
    curr = head->next;          /* curr = start of list */
    head->next = NULL;          /* set list to empty */
    while(curr != NULL){        /* delete nodes */
        head = curr;
        curr = curr->next;
        free(head);
    }
}

int main()
{
node dummy = {NULL, -1};
node * head = &dummy;
int i;
    srand((unsigned int)time(NULL));
    for(i = 0; i < 20; i++)
        sorted_insert(head, rand()%2000);
    print(head);
    delete(head);
    return 0;
}

【讨论】:

    猜你喜欢
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2013-04-04
    • 2012-12-29
    • 1970-01-01
    相关资源
    最近更新 更多