c++ 为什么我的代码对此问题不起作用?

xzv2uavs  于 2023-03-20  发布在  其他
关注(0)|答案(3)|浏览(165)

这些数字以自然数表示。按出现的升序列出这些数字的十进制表示法中出现的数字。如果两个数字出现的次数相同,则先显示较小的数字。
示例:

五一二四二二九一三二二四五三四
出局
5 9 1 3 4 2
这是我的代码:

#include <iostream>

using namespace std;

int v1[10],v2[10],lim,x,ok;

int main()
{
    cin>>lim;

    for(int i=1; i<=lim; i++)
    {
        cin>>x;

        while (x>0)
        {
            v1[x&10]++;
            v2[x%10]=x%10;
            x=x/10;
        }
    }
    while (!ok)
    {
        ok=1;

        for(int i=0; i<=lim; i++)
        {
            if(v1[i]>v1[i+1])
            {
                swap (v1[i],v1[i+1]);
                swap (v2[i],v2[i+1]);
                ok=0;
            }
        }
    }
    ok=0;
    while (!ok)
    {
        ok=1;

        for(int i=0; i<lim; i++)
        {
            if(v2[i]>v2[i+1])
                if(v1[i]==v1[i+1])
                    swap (v2[i],v2[i+1]);
        }
    }
    for (int i=0; i<=10; i++)
    {
        if(v2[i]!=0)
            cout<<v2[i]<<" ";
    }
}

它不会按我想要的方式排序
我试过两次了

w8biq8rn

w8biq8rn1#

  • 您应该递增v1[x%10](使用模),而不是v1[x&10](使用位与)
  • 这两个排序应该针对v1v2的10个元素进行,而不是针对lim+2lim+1元素进行。
  • v2[10]超出范围,因此您不能访问它。

固定代码:

#include <iostream>

using namespace std;

int v1[10],v2[10],lim,x,ok;

int main()
{
    cin>>lim;

    for(int i=1; i<=lim; i++)
    {
        cin>>x;

        while (x>0)
        {
            // use modulo instead of bitwise AND
            //v1[x&10]++;
            v1[x%10]++;
            v2[x%10]=x%10;
            x=x/10;
        }
    }
    while (!ok)
    {
        ok=1;

        // sort 10 elements instead of lim+2
        //for(int i=0; i<=lim; i++)
        for(int i=0; i<9; i++)
        {
            if(v1[i]>v1[i+1])
            {
                swap (v1[i],v1[i+1]);
                swap (v2[i],v2[i+1]);
                ok=0;
            }
        }
    }
    ok=0;
    while (!ok)
    {
        ok=1;

        // sort 10 elements instead of lim+1
        //for(int i=0; i<lim; i++)
        for(int i=0; i<9; i++)
        {
            if(v2[i]>v2[i+1])
                if(v1[i]==v1[i+1])
                    swap (v2[i],v2[i+1]);
        }
    }
    // deal with the 10 elements instead of 11
    //for (int i=0; i<=10; i++)
    for (int i=0; i<10; i++)
    {
        if(v2[i]!=0)
            cout<<v2[i]<<" ";
    }
}

实际上,第二次排序可以删除,因为您使用的是稳定的冒泡排序,并且v2中的数字在第一次排序之前就已经按升序排列了。
还要注意的是,即使05 120 34 56 78 90一样出现在输入中,程序也不会打印它。如果你想在输出中包含0,你应该使用if(v1[i]!=0)而不是if(v2[i]!=0)。即使做了这样的修改,当输入中有零或负数时,程序也不会工作。

siotufzp

siotufzp2#

你的代码产生错误输出的更深层次的原因是它太复杂了。这里只列举主要的复杂因素:
使用神秘的变量名会使代码更难读。难读的代码更容易有bug。
你可以从头开始实现而不是使用现有的算法。手动实现算法而不是使用标准库中的工具的代码更有可能有bug。
C-数组有很多怪癖,而且很复杂。也许最重要的是,它们需要你分别跟踪它们的大小(实际上,大小是现成的,因为它是类型的一部分,但那很麻烦)。使用C-数组而不是标准容器的代码更容易有bug。
因为你只需要处理单个数字,所以把输入读成字符串会更简单。要计算出现的次数,你可以使用std::map

std::map<char,unsigned> counts;
for (int i=0;i<n;++i) {
    std::string number;
    std::cin >> number;
    for (char digit : number) ++counts[digit];
}

counts将所有数字作为键,将它们的出现作为Map值。它是根据数字排序的(注意,unordered_map也可以,但顺序还不是所需的)。
为了根据出现次数进行排序,我们填充一个Map,该Map将出现次数作为键,将数字作为Map值,因为两个不同的数字cabn具有相同的出现次数,并且因为输出中较小的数字应该首先出现,所以我们可以使用set<char>来存储数字:

std::map<unsigned,std::set<char>> digits;
for (const auto& elem : counts) {
    digits[elem.second].insert(elem.first);
}

现在,输出只是一个嵌套循环,用于迭代所有出现的数字,以及对于每个出现的数字出现在集合中:

for (const auto& elem : digits) {
    for (const auto& digit : elem.second) {
        std::cout << digit << " ";
    }
}

这就是所需要的全部内容。代码中唯一遗漏的部分是阅读n的值。您只需要将这些部分加在一起。

knsnq2tg

knsnq2tg3#

对于给定的测试用例(5 124 229 1322 4 534),模型答案(5 9 1 3 4 2)似乎是错误的。
如果你愿意的话,你几乎可以完全使用字符来工作:它们的排序与数字相同。大量使用标准库例程,如stable_sort:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;

int main()
{
   string test = "5 124 229 1322 4 534";
   int freq[10]{};
   for ( char c : test ) if ( isdigit( c ) ) freq[c-'0']++;
   string digits = "0123456789";
   stable_sort( digits.begin(), digits.end(), [&freq]( char a, char b ){ return freq[a-'0'] < freq[b-'0']; } );
   for ( char c : digits ) if ( freq[c-'0'] ) cout << c << ' ';
}
9 1 3 5 4 2

相关问题