在链表中排序插入

时间:2017-10-19 22:35:43

标签: c linked-list

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

#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

2 个答案:

答案 0 :(得分:0)

代码使用虚拟头节点。通常虚拟节点在列表之前,而不是用于终止列表。代码不应该在主程序中改变头部,并且sorted_insert不需要返回指向节点的指针,因为它更新head-&gt; next,这是指向第一个节点的实际指针。 sorted_insert应设置prev = ptr和current = ptr-&gt; next。要插入的检查应该是newNode-&gt; data&lt; current-&gt; data(如果是这样,请在当前之前插入newNode)。没有必要设置head-&gt; 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;
}

答案 1 :(得分:0)

你的分类插入比它需要的要复杂一点。由于您在末尾使用虚拟节点,因此您只需要测试2个条件(如果您考虑将第1个节点添加为条件,则为3个)。

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

  2. 否则,只需遍历列表设置current=current->next,直到newNode->data < current->next->data。然后只需在此时添加newNode

  3. 简化并清除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++?

    3. 最后,不是打印node->datastdout来验证您的节点是按排序顺序插入的,而是养成编写和使用简单检查顺序的简单验证例程的习惯如果发现错误,就会抱怨(以某种有意义的方式)。您可以使用print函数的变体来比较previous->data > current->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");