首页 > 解决方案 > 在输入中列出一个列表,删除所有重复项并计算它们的数量

问题描述

我试图实现这个功能,但有时我在运行时遇到问题。我需要输入一个像 1-2-3-2-4-6-1-2 这样的列表,并且该列表应该修改为 1-2-3-4-6 所以每个节点一次,我应该保存如何很多次是一个节点重复所以例如 1 重复 2 次 2 重复 3 次等。但有时它不起作用我不明白为什么。如果你按照我刚刚写的内容运行它,你会看到问题:多少节点:5 比写 1、1、2、4、2 和输出应该是 1、2 -> 2、2 -> 4(这意味着1重复两次,2重复两次,4重复1次)。如果我输入 1、2、3、2、1,我会得到“正确的输出”加上一个垃圾值。数字越高,它不起作用的可能性越大:(

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

typedef struct Node{
   int val;
   int rip;
   struct Node *next;
} node;

node *modify(node *head);

void print(node *head2);

int main(){

   int m, i;

   printf("How many nodes: \n");
   scanf("%d", &m);

   node *head = NULL;
   head = (node *)malloc(sizeof(node));
   node *temp = head;
   node *head2 = NULL;
  for(i=0; i < m; i++){
       temp->next = (node *)malloc(sizeof(node));
       printf("Write the value in position %d: \n", i);
       scanf("%d", &temp->val);
       temp = temp->next;
       temp->next = NULL;  
   }

   head2 = modify(head);

   print(head2);

   return 0;
}

node *modify(node *head){

   int counter, pass, m;

   node *curr = head;
   node *track = head;

while (track->next != NULL){
       counter = 0;
       pass = 0;
       m = track->val;
       while((curr)->next != NULL){
           if(m == (curr)->val){
               pass++;
               counter++;
               if(pass > 1){
                   node *removed = curr;
                   curr = (curr)->next;
                   free(removed);
               }
               if(pass == 1)
                   curr = curr->next;
           }
           else{
               curr = (curr)->next;
           }    
       }
       track->rip = counter;
       track = track->next;
       curr = track;
   }

return head;
}

void print(node *head2){

   while(head2->next != NULL){
       printf("%d, %d -> ", head2->val, head2->rip);
       head2 = head2->next;
   }
   printf("\n");
}

标签: c

解决方案


错误在这里:

           if(pass > 1){
               node *removed = curr;
               curr = (curr)->next;
               free(removed);
           }

此代码释放了应该删除的节点,但没有将前一个节点链接到下一个节点,因此列表变得不正确。由于您不重新使用已释放的内存,它会保留其先前的值,但您确实会通过使用它来调用未定义的行为。

您必须跟踪以前的记录才能修复链接。一个可能的代码可能是:

while (track->next != NULL){
   counter = 0;
   pass = 0;
   node *old = NULL;
   m = track->val;
   curr = track;
   while((curr)->next != NULL){
       node *next = curr->next;
       if(m == (curr)->val){
           pass++;
           counter++;
           if(pass > 1){
               old->next = next;  // old cannot be NULL because pass>1
               free(curr);
               curr = NULL;
           }
       }
       if (curr != NULL) old = curr;
       curr = next;
   }
   track->rip = counter;
   track = track->next;
}

推荐阅读