【问题标题】:one element of list is sorted others aren't列表的一个元素已排序其他元素未排序
【发布时间】:2017-01-07 19:02:34
【问题描述】:

好的,所以我正在编写一个程序,我必须输入 n 个学生的姓名、名字和成绩。完成后,我必须按字母顺序排列它们,如果名称匹配,则在第一个之后名字。然后我有另一个选项来按成绩排序。这是我到目前为止的代码:

#include<iostream>
#include<string.h>
#include<conio.h>
#include<stdio.h>

using namespace std;

struct student
{
 char name[30];
 char firstname [50];
 int grade;
}s[50]; 

int i,n,o,done=0;


void add_student()
{
  cout<<"Number of students:"<<" ";
  cin>>n;
  cout<<endl;


   for(i=1; i<=n; i++)
    {

    fflush(stdin);
    cout<<"Student"<<" "<<i<<":"<<endl;

    cout<<"name of student:"<<" ";
    gets(s[i].name);

    cout<<"first name of student:"<<" ";
    gets(s[i].firstname);

    cout<<"grade of student:"<<" ";
    cin>>s[i].grade;
    cout<<endl;
   }
}


void sort_name()
{
 char temp[30];
  while(!done)
  {
    done=1;
    for(i=1; i<n; i++)
     {
    if(strcmp(s[i].name,s[i+1].name)>0)
        {
    strcpy(temp,s[i].name);
    strcpy(s[i].name,s[i+1].name);
    strcpy(s[i+1].name,temp);

        }
     }
  }

for(i=1; i<=n; i++)
  {
    cout<<"Student"<<" "<<i<<":"<<endl;
    cout<<"Name"<<":"<<s[i].name<<endl;
    cout<<"Firstname"<<":"<<s[i].firstname<<endl;
    cout<<endl;
  }
}


void sort_grade()
 {
 int temp;
  while(!done)
  {
    done=1;
    for(i=1;i<n;i++)
    {
        if(s[i].grade>s[i+1].grade)
        {
            temp=s[i].grade;
            s[i].grade=s[i+1].grade;
            s[i+1].grade=temp;
            done=0;
        }
    }
}

for(i=1; i<=n; i++)
{
    cout<<"Student"<<" "<<i<<":"<<endl;
    cout<<"Name"<<":"<<s[i].name<<endl;
    cout<<"Firstname"<<":"<<s[i].firstname<<endl;
    cout<<"Grade"<<":"<<s[i].grade<<endl;
    cout<<endl;
}


}

void list_students()
{
 int i;
 for(i=1; i<=n; i++)
{
    cout<<"Student"<<" "<<i<<":"<<endl;
    cout<<"Name"<<":"<<s[i].name<<endl;
    cout<<"Firstname"<<":"<<s[i].firstname<<endl;
    cout<<"Grade"<<":"<<s[i].grade<<endl;
    cout<<endl;
}
}



int main()
{
 do
 {

    cout<<"Menu:"<<endl;
    cout<<"1.Add students"<<endl;
    cout<<"2.Sort by name"<<endl;
    cout<<"3.Sort by grade"<<endl;
    cout<<"4.List  students"<<endl;
    cout<<"5.Exit"<<endl<<endl;
    cout<<"Pick option : ";
    cin>>o;
    cout<<endl;

        switch (o)
            {   
                case 1:add_student();
                break;
                case 2:sort_name();
                break;
                case 3:sort_grade();
                break;
                case 4:list_students();
                break;
            }
  }while (o!=5);
}

问题是每当我按成绩排序时,例如学生 A 的成绩为 9,学生 B 的成绩为 7,排序后它会告诉我学生 A 的成绩为 7,学生 B 的成绩为 9。我知道我我告诉排序功能只排序等级而不是名称,但我不知道如何解决它。这可能非常简单,我认为它涉及某种指针,但我真的不知道。哦,如果你能如果名字相同,请提供一些关于如何在名字之后进行排序的信息。如果有人可以帮助我,我将非常感激。提前谢谢!!(如果有人可以给我任何关于这个问题的指示看起来像 ci 真的很感激)

【问题讨论】:

  • 是时候熟悉调试器了。
  • 这不是'c',请不要这样做fflush(stdin);
  • 你知道在c++中数组的第一个元素是由0索引的吗?
  • 我只从 1 开始,因为学生的列表会从 0 开始,比如学生 0、学生 1 等等,我会那样做。如果不好,我不会再这样做了fflush 的情况。我放了 c 标签,因为我的许多书,甚至我的一些老师都未能解释 c 和 c++ 之间的区别,他们只是让它们看起来有点像我知道不是这种情况。无论如何,谢谢大家的帮助。这实际上是我第一次来这里,你们让我想要改进。继续努力!

标签: c++


【解决方案1】:

您应该交换整个结构,而不是只交换结构的一部分(sort_grade() 内部的s[i].gradesort_name() 内部的s[i].name)。它应该类似于以下内容:

void swap(int n, int m)
{
    char temp_string[50];
    int  temp_int;

    strcpy(temp,s[n].name);
    strcpy(s[n].name,s[m].name);
    strcpy(s[m].name,temp);

    strcpy(temp,s[n].firstname );
    strcpy(s[n].firstname ,s[m].firstname );
    strcpy(s[m].firstname ,temp);

    temp_int = s[n].grade;
    s[n].grade = s[m].grade;
    s[n].grade = temp_int;
}

void sort_name()
{
    char temp[30];
    while(!done)
    {
        done=1;
        for(i=1; i<n; i++)
        {
            if(strcmp(s[i].name,s[i+1].name)>0)
            {
                swap(i, i+1);
            }
       }
   }
}

【讨论】:

  • 结构是可赋值的,所以swap只需要student temp = s[n]; s[n] = s[m]; s[m] = temp;。(但标准库中已经有一个swap可供使用。)
  • 非常感谢您的帮助。我才开始编码,我读的大多数书都非常模糊。我希望我也可以学习并帮助他人。
【解决方案2】:

代码中有很多错误的地方。

在这里,我只是为你修复了它们,但它可能受到了我的编码风格的影响:

标题:

 #include <iostream>
 #include <cstring> //not <string.h>
 #include <cstdio> //not <stdio.h>
 //#include <conio.h> //you don't use any functionality from this header
 #include <limits>
 #include <cinttypes>

命名空间:

// dont use "using namespace std;", it's considered bad (here it might not be visible)

结构还可以吗?我认为:

struct student
{
    char name[30];
    char firstname [50];
    int grade;
}s[50];

不要依赖全局变量(不过这个程序模型需要n

int /*i,*/n=0/*,o,done=0*/; //don't declare global variables if you don't need them to be global

修复了add_student()(很多错误):

void add_student()
{
    std::cout<<"Number of students:"<<" ";
    std::cin>>n;
    std::cout<<std::endl;
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //this is how you flush in c++

    for(int i=0/*1*/; i</*=*/n; i++) //declare iterator in loop
    {                       //also, first element index is 0, not 1!

        //fflush(stdin); //NEVER do that in C++, std::std::endl flushes output anyways
        std::cout<<"Student"<<" "<<i+1<<":"<<std::endl/*;*/ //dont spam std::cout too much
              /*std::cout*/<<"name of student:"<<" ";      //just go to next line and start with "<<"
        std::gets(s[i].name);

        std::cout<<"first name of student:"<<" ";
        std::gets(s[i].firstname);

        std::cout<<"grade of student:"<<" ";
        std::cin>>s[i].grade;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout<<std::endl; //this std::std::endl call flushes output, so that "C flushin" didn't do anything
    }
}

排序函数(很多错误):

void sort_name()
{
    bool done = false; //prefer bool over int for logical expressions
    /*char temp[30];*/ //not gonna use this, you need whole student, not only name
    student temp;
    while(!done)
    {
        // this whole section is wrong, you just go around swapping
        // students names, not students themselfs
        //        done=1;
        //        for(i=0/*1*/; i<n-1; i++)
        //        {
        //            if(strcmp(s[i].name,s[i+1].name)>0)
        //            {
        //                strcpy(temp,s[i].name);
        //                strcpy(s[i].name,s[i+1].name);
        //                strcpy(s[i+1].name,temp);

        //            }
        //        }
        done = true;
        for(int i=0; i<n-1; ++i)
        {
            if(strcmp(s[i].name, s[i+1].name)>0)
            {
                std::cout << "swapping" << std::endl;
                temp = s[i];
                s[i] = s[i+1];
                s[i+1] = temp;
                done = false;
            }
        }
    }

    for(int i=0/*1*/; i</*=*/n; i++)
    {
        std::cout<<"Student"<<" "<<i+1<<":"<<std::endl
            <<"Name"<<":"<<s[i].name<<std::endl
            <<"Firstname"<<":"<<s[i].firstname<<std::endl
            <<std::endl;
    }
}


void sort_grade()
{
    bool done = false;
    student temp;

    //exact same mistakes like in sort_name()
    while(!done)
    {
        done = true;
        for(int i=0; i<n-1; ++i)
        {
            if(s[i].grade > s[i+1].grade)
            {
                temp = s[i];
                s[i] = s[i+1];
                s[i+1] = temp;
                done = false;
            }
        }
    }

    for(int i=0/*1*/; i</*=*/n; i++)
    {
        std::cout<<"Student"<<" "<<i+1<<":"<<std::endl
            <<"Name"<<":"<<s[i].name<<std::endl
            <<"Firstname"<<":"<<s[i].firstname<<std::endl
            <<"Grade"<<":"<<s[i].grade<<std::endl
            <<std::endl;
    } 
}

list_students() 函数(cout 垃圾邮件和索引再次移位):

void list_students()
{
    for(int i=0/*1*/; i</*=*/n; i++)
    {
        std::cout<<"Student"<<" "<<i+1<<":"<<std::endl
            <<"Name"<<":"<<s[i].name<<std::endl
            <<"Firstname"<<":"<<s[i].firstname<<std::endl
            <<"Grade"<<":"<<s[i].grade<<std::endl
            <<std::endl;
    }
}

还有main()(将int o设为局部变量并修复cout垃圾邮件):

int main()
{
    int o;
    do
    {
        //please, don't spam std::cout like that, it hurts
        std::cout<<"Menu:"<<std::endl
            <<"1.Add students"<<std::endl
            <<"2.Sort by name"<<std::endl
            <<"3.Sort by grade"<<std::endl
            <<"4.List  students"<<std::endl
            <<"5.Exit"<<std::endl<<std::endl
            <<"Pick option : ";
        std::cin>>o;
        std::cout<<std::endl;

        switch (o)
        {
        case 1:add_student();
            break;
        case 2:sort_name();
            break;
        case 3:sort_grade();
            break;
        case 4:list_students();
            break;
        }
    }while (o!=5);
}

简而言之,还有很长的路要走!但是学习你的代码,阅读一些好书,这样你就可以改进。

编辑:

标题:

cstdio stdio.h namespace

命名空间:

Why is "using namespace std" considered bad practice?

全局变量:

Are global variables bad?

C/C++ 中的索引:

Why does the indexing start with zero in 'C'?

C++中刷新输入/输出和cin/get~问题解决方案:

(输出)

C++: "std::endl" vs "\n"

(输入)

cin and getline skipping input

反垃圾邮件:

http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt

交换结构:

c++ sort with structs

【讨论】:

  • 非常感谢您的洞察力。我才刚刚开始编程,我读过的许多书只是涵盖了非常基本的东西,但我正在尝试并且我想改进
  • 没关系 :) 我会发布一些关于我评论/使用的东西的很好解释的链接。
  • 再次感谢。我会研究你给我的代码和链接,我会尝试找到一些更好的书并向我的老师提出更多问题。谢谢谢谢:D
【解决方案3】:

冒泡排序的一般问题

  1. 您使用标准进行排序,但只交换标准而不交换其他特征! temp 在这两种情况下都应该是 struct student
  2. 索引移动 1。在这两种排序情况下,您都是从 1 开始到 n-1,但索引为 ii+1:缺少第一个元素并且数组溢出一个。

而且“冒泡排序”这个名字是错误的(缺少做作的做作):

我会这样做

while(!done)
  {
    done = 1;
    for(i=0; i < n-1; i++)
      {
        if(strcmp(s[i].name, s[i+1].name) > 0)
          {
            done = 0; // still work to do
            temp = s[i];
            s[i] = s[i+1];
            s[i+1] = temp;
          }
      }
  }

排序等级也是错误的:修正版本:

void sort_grade()
  {
    struct student temp;
    while(!done)
      {
        done = 1;
        for(i=0; i < n-1; i++)    // loop boundaries were not OK
          {
            if(s[i].grade > s[i+1].grade)
              {
                temp = s[i];
                s[i] = s[i+1];
                s[i+1] = temp;
                done = 0;
              }
          }
      }
  }

更不用说 C++ 有使用标准的高效排序功能,比这要好得多(除非你必须这样做)

【讨论】:

  • 我知道还有其他更好的排序功能,但问题是它必须用这个来完成。也感谢你指出我的错误。我是新手,虽然我大多知道什么我的代码有问题我仍然不知道如何修复它或如何改进它。仍然缺乏经验
【解决方案4】:

在交换时使用类似 memcpy() 的函数并交换整个结构而不是 name / gRade

【讨论】:

  • 永远不要在结构上使用 memcpy。
  • 它只适用于包含 POD 对象/纯 C 的结构。尝试复制包含 vectorstring 的结构,此时它会严重崩溃。
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
相关资源
最近更新 更多