排序的算法有很多种,如冒泡排序、选择排序、插入排序等。今天我先学习了第一个——冒泡排序,下面我们用C++解决这样一个问题。
首先,我们先了解一下冒泡排序,这是一种简单的排序方法,其算法具体如下:
第一、比较相邻的元素,如果第一个比第二个大,就交换他们两个,否则就不交换
第二、对每一对相邻元素做同样的比较,从最开始的第一对到结尾的最后一对,这样下来最后的元素就是数组中最大的数
第三、对数组中所有的元素重复上述步骤,除了最后一个
第四、持续对越来越少的元素重复上述步骤,直到没有任何一组数字需要比较
由此下来,我们就能得到从小到大排序好的数,下面我们开始操作:
首先我们要初始化一个随机排列的数组,因此我们需要用到随机数,这里我们使用时间作为种子:
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
设计主函数,先来初始化一个随机数组:
int main(){
int i;
const int CNT=20;
const int MAX=50;
int num[CNT];
for (i=0;i<CNT;i++){
num[i]=rand()%MAX+1;//随机化大小为20的数组,范围为0~50
}
接下来构造算法:
int temp;
for (int j=CNT-1;j>=0;j--){ //依次遍历
for (i=0;i<CNT-1;i++){//从前两行开始比较
if(num[i]>num[i+1]){//交换符合条件的一对相邻数据
temp=num[i+1];
num[i+1]=num[i];
num[i]=temp;
}
}
加上打印输出的代码:
for (int i=0 ;i<CNT;i++){
cout<<"num["<<i<<"]:";
for (int n=0;n<num[i];n++)cout<<"*";
cout<<num[i]<<endl;
}
合并后的代码就是:
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main(){
int i,temp;
const int CNT=20;
const int MAX=50;
int num[CNT];
for (i=0;i<CNT;i++){
num[i]=rand()%MAX+1;//随机化大小为20的数组,范围为0~50
}
cout<<"排序前:\n";
for (int i=0 ;i<CNT;i++){
cout<<"num["<<i<<"]:";
for (int n=0;n<num[i];n++)cout<<"*";
cout<<num[i]<<endl;
}
for (int j=CNT-1;j>=0;j--){ //依次遍历
for (i=0;i<CNT-1;i++){//从前两行开始比较
if(num[i]>num[i+1]){//交换符合条件的一对相邻数据
temp=num[i+1];
num[i+1]=num[i];
num[i]=temp;
}
}
}
cout<<"排序后:\n";
for (int i=0 ;i<CNT;i++){
cout<<"num["<<i<<"]:";
for (int n=0;n<num[i];n++)cout<<"*";
cout<<num[i]<<endl;
}
}
编译运行,效果如图所示:
但是,实验并没有结束,这种不知道过程只知道结果的输出方式我想不仅是我,大家也不会满意的,所以我想找到一种方式,让整个过程可视化。
首先我想到的是让我们正在进行if运算(判断相邻的两个数的大小并决定是否要交换)的数据高亮,然后在每次if判断后刷新一次输出,以达到可视化的程度,接下来让我们逐步解决问题。
问题一、如何高亮特定的数组?
已经有人做出了回答,这里我们引用他的代码:(各个数字代表的颜色请点击超链接)
void Set_Color(short color) //自定义函根据参数改变字体颜色
{
if(x>=0 && x<=15) //参数在0-15的范围颜色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
else //默认的颜色白色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
于是我们可以通过改变颜色来突出正在进行判断的数据
需要注意的是我们这里要额外添加一个头文件#include <windows.h>
问题二、如何刷新界面
我们知道,以往的输出都是在原先输出的基础上继续向后写入,所以我们要通过某种特定的方式改变输出的位置,以覆盖原先的输出,达到动态刷新的效果。
不出所料,也有人对此给出了解决方法,这里我们还要引入一个函数并将其命名为gotoxy()
:
void gotoxy(int y,int x){
COORD pos;
pos.X=x;
pos.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
其中y代表行,x代表列,这样,我们就能将输出调整到任何我们想要的位置
至此,两大问题已经解决,下面要做细化代码的过程。
首先将输出和改变颜色合并起来,这里再次构造一个函数:
void shuchu(int num[],int m=100){//这里的m指的是正在排序的数所在的行数。m默认值为100,即不在0~15内,结合函数主体可知默认为白色。
for (int i=0;i<CNT;i++){//逐行输出
cout<<" \r";//用空格覆盖原先的输出,达到类似清除的效果
if(i==m||i==m+1){Set_Color(12);}//在此判断该行是否为正在排序的行,如果是则变换颜色为红色
else{Set_Color(7);} //否则仍为白色
cout<<"num["<<i<<"]:";
for (int n=0;n<num[i];n++)cout<<"*";
cout<<num[i]<<endl;
}
}
为了达到更好的效果,我们先将原始数组输出,并加上system("pause");
语句,以等待用户按任意键继续进行,之后开始动态刷新,在每次排序时将输出位置调整并重新输出已经调整过改变颜色后的输出。
#include<iostream>
#include<cstdlib>
#include<ctime>
#include <windows.h>
using namespace std;
const int CNT=20;//数组个数
const int MAX=50;//数的范围为0~50
/*初始化需要的函数*/
void Set_Color(short color);
void gotoxy(int y,int x);
void shuchu(int num[],int m=100);//m默认值为100,即不在0~15内,结合函数主体可知为白色
int main(){
int i,n;
int temp;
srand((unsigned)time(NULL));//初始化种子
int num[CNT];
for (i=0;i<CNT;i++){
num[i]=rand()%MAX+1;//随机化数组
}
cout<<"排序前:\n" ;
shuchu(num);//打印出生成的随机数组
system("pause");
gotoxy(0,0);
cout<<"排序中……";
for (int j=CNT-1;j>=0;j--){ //依次遍历
for (i=0;i<CNT-1;i++){//从前两行开始比较
gotoxy(1,0);//回到初始位置(第一行为“排序中”,故从第二行开始)
shuchu(num,i);//重新输出
Sleep(5);//等待5毫秒,以体现刷新效果
if(num[i]>num[i+1]){//交换符合条件的一对相邻数据
temp=num[i+1];
num[i+1]=num[i];
num[i]=temp;
}
}
}
gotoxy(0,0);
Set_Color(9);
cout<<"排序后: \n" ;
for (i=0;i<CNT;i++){
cout<<"num["<<i<<"]:";
for (n=0;n<num[i];n++)cout<<"*";
cout<<num[i]<<endl;
}
cout<<" ";
}
void Set_Color(short color) //自定义函根据参数改变字体颜色
{
if(color>=0 && color<=15) //参数在0-15的范围颜色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
else //默认的颜色白色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
void gotoxy(int y,int x){
COORD pos;
pos.X=x;
pos.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void shuchu(int num[],int m){
for (int i=0;i<CNT;i++){
cout<<" \r";
if(i==m||i==m+1){Set_Color(12);}
else{Set_Color(7);}
cout<<"num["<<i<<"]:";
for (int n=0;n<num[i];n++)cout<<"*";
cout<<num[i]<<endl;
}
}
以上