作业题:
实现一个排序系统
相关知识:
1、接口(C++叫抽象类)
2、排序算法:冒泡排序、快速排序、直接插入排序、归并排序
3、工厂模式
要求:
A、定义一个排序抽象类(即接口),所有的排序函数继承实现这个抽象类
B、将排序函数封装成一个工厂类
输入:
10
10 9 8 76 5 4 3 2 1
注:第一个数是数组元素个数,第二个是数组中元素
输出:
1 2 3 4 56 7 8 9 10
训练目标:
理解面向对象的思想
学会同类的继承和接口的使用
问题分析:
(一) 四种排序算法的原理是什么?
(二) 什么叫抽象类?如何定义它?它有什么作用?
(三) 什么叫工厂模式?它是如何实现的?
(四) 编写的过程中要注意哪些细节?<在代码中会有注释>
问题解决(一)四种排序算法的原理是什么?
冒泡排序<BubbleSort>——从小到大
1、基本思想:两个数两个数比较大小,较大的数下沉,较小的数冒起来。
2、过程:
A、比较相邻的两个数据,如果第一个数比第二的数大就交换位置。
B、从前到后两两比较,一直比较到最后两个数据 。最终最大的数据被交换到最后的位置,这样最后一个最大数的位置就排好了。
C、继续重复上述操作,依次将第n-1,n-2…2,1个最大数排好位置。
3、图示:
4、代码实现:
void BubbleSort(int a[],int n)
{
int i,j,temp=0; //定义变量的时候顺便初始化,Int i=0,j=0,temp =0;这里也许用处不大,但是要养成重视初始化变量的习惯
for(i=0;i<n-1;i++)
{
int count=0;//是否交换的标志
for(j=0;j<n-1-i;j++)
{
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
count=1;
}
}
if(count==0)//若循环一轮结束后,没有发生交换,则说明该数据顺序已经排好,无需继续进行下去
break;
}
}
快速排序<QuickSort>
1、 基本思想:快速排序采用的是分治法,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
2、过程:
A、设置两个变量i、j,排序开始的时候:i=0,j=n-1;
B、以第一个数组元素作为关键数据,赋值给key,即 key=a[0];
C、从j开始向前搜索,即由后开始向前搜索(j=j-1即j--),找到第一个小于key的值a[j],a[j]与a[i]交换;
D、从i开始向后搜索,即由前开始向后搜索(i=i+1即i++),找到第一个大于key的a[i],a[i]与a[j]交换;
E、重复第3、4、5步,直到 i=j; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。找到并交换的时候i, j指针位置不变。另外当i=j这过程一定正好是i++或j--完成的最后交换,到此循环结束。)
3、示意图:
4、代码实现:
void QuickSort(int a[],int left,int right)
{
if(left<right)
{
int key=a[left];
int i=left;
int j=right;
while(i<j)
{
while(i<j&&a[j]>=key)
{
j--;
}
a[i]=a[j];
while(i<j&&a[i]<=key)
{
i++;
}
a[j]=a[i];
}
a[i]=key;
QuickSort(a,left,i-1);
QuickSort(a,i+1,right);
}
}
直接插入排序<InsertionSort>
1、基本思想:在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。这样反复循环,直到全部排好序。
2、过程:
A、假设数组中a[0]就是排序好的第一个数,用a[1]和a[0]比较,如果a[1]<a[0]则a[0]和a[1]数值交换。
B、然后再用a[2]先和a[1]比较如果a[2]>a[1];则跳出循环,如果a[2]<a[1],a[2]和a[1]就交换,在比较a[1]和a[0],如果a[1]<a[0],那么a[1]和a[0]交换。如此循环直到数组全部有序。
3、图示:
4、代码实现:
void InsertionSort(int a[],int n)
{
int temp;
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j>0;j--)
{
if(a[j]<a[j-1])
{
temp=a[j-1];
a[j-1]=a[j];
a[j]=temp;
}
else
break;
}
}
}
归并排序<MergeSort>
1、基本思想:归并排序是建立在归并操作上的一中有效的排序算法。该算法是采用分治的思想。
2、过程:
A、首先要考虑如何将2个有序数列合并。只要比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果数列为空,那直接将另一个数列的数据依次取出即可。
B、解决了上面合并的问题,再来看归并排序,其中的基本思想就是将数组分成2组A、B,如果这2组数据都是有序的,那么就可以很方便的将这2组数据进行排序。
C、如何使这2组组内数据有序?可以将A,B组各自再分成2组。依次类推,当分出来的小组只有1个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的2个小组就可以了。这样通过先分解数列,再合并数列就完成了归并排序。
3、图示:
4、代码实现:
//合并 :将两个序列a[first-middle],a[middle+1-last]合并
void Merge(int a[],int first,int middle,int last,int temp[])
{
int i = first;
int m = middle;
int j = middle+1;
int n = last;
int k = 0;
while(i<=m && j<=n)
{
if(a[i] <= a[j])
{
temp[k] = a[i];
k++;
i++;
}
else
{
temp[k] = a[j];
k++;
j++;
}
}
while(i<=m)
{
temp[k] = a[i];
k++;
i++;
}
while(j<=n)
{
temp[k] = a[j];
k++;
j++;
}
for(int i=0;i<k;i++)
{
a[first + i] = temp[i];
}
}
void MergeSort(int a[],int first,int last,int temp[])
{
if(first < last)
{
int middle = (first + last)/2;
MergeSort(a,first,middle,temp); //左半部分排好序
MergeSort(a,middle+1,last,temp); //右半部分排好序
Merge(a,first,middle,last,temp); //合并左右部分
}
}
问题解决(二)什么叫抽象类?如何定义它?它有什么作用?
抽象类:含有纯虚函数的类叫做抽象类。
如:class SORT
{
Public:
VirtualSort ( int a[] , int n ) = 0 ;//在父类中只做声明,函数体为空,必须在子类中实现
Virtual~SORT ( )
{
Cout<< ”Release the SORT object.”<<endl ;//验证该虚析构函数是否被调用
}//定义一个虚析构函数,在运行多态时能够通过delete父类指针,释放子类对象,避免了内存的泄露
} ;
抽象类的作用:有利于多态性,抽象的型别统一类型,来进行操作,有利于以后的扩展,移植,复用。
问题解决(三)什么叫工厂模式?它是如何实现的?
工厂模式:为创建对象提供过渡接口,以便将创建的对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。就这道题来讲:即一个工厂是生产排序功能的,你现在需要排序一组数,你就跟工厂说给我用冒泡法排序它,然后工厂就会给你一个用冒泡法排好序的数组,如果你跟工厂说给我用快排排序它,工厂就会给你一个用快排排序好的数组。
工厂模式示意图:
编写代码:
#include <iostream>
using namespace std;
#include <stdlib.h>
enum SORTTYPE { Bubble =1, Quick=2, Insertion=3, Merge=4,Selection=5,Exchange=6 };
void menu(); //显示用户界面
template <class T> //因为四种排序算法中的形参类型可能不同,所以要定义函数模板
class SORT //定义SORT抽象类 作为基类 下面的四个排序类是它的派生类 继承它的Sort(....);
{
public:
virtual void Sort(T a[], int n) = 0; //在父类中声明纯虚函数,子类必须实现它,否则子类不能实例化,子类继承Sort(...)时形参要和父类保持一致
virtual ~SORT() //定义虚析构函数,通过delete父类指针释放子类对象
{
cout << "Release the base sort object" << endl;//检验是否释放了SORT对象
}
};
template <class T>
class BubbleSort :public SORT <T> //定义冒泡排序类 public继承SORT类 要继承SORT类中的成员函数模板 每个派生类的声明都要加上<T>
{
public:
void Sort(T a[], int n); //冒泡排序,先声明,实现放在main函数的下面,这样能够加强程序的可读性
~BubbleSort()
{
cout << "Release Bubble Sort object" << endl; //检验是否释放BubbleSort的对象
}
};
template <class T>
class QuickSort :public SORT<T> //定义快速排序类 public继承SORT类 要继承SORT类中的成员函数模板 每个派生类的声明都要加上<T>
{
public:
void Sort(T a[], int n);
void qsort(T a[], int left, int right); //快速排序的形参和Sort(...)不一致,所以快排算法重新声明一个函数,然后再在Sort(...)调用
~QuickSort()
{
cout << "Rlease QuickSort object" << endl; //检验是否释放了QuickSort的对象
}
};
template <class T>
class InsertionSort :public SORT<T> //定义插入排序类 public继承SORT类 要继承SORT类中的成员函数模板 每个派生类的声明都要加上<T>
{
public:
void Sort(T a[], int n); //插入排序的声明,实现放在main函数的下面,这样能够加强程序的可读性
~InsertionSort()
{
cout << "Release Insertion Sort object " << endl; //检验是否释放了InsertionSort的对象
}
};
template <class T>
class MergeSort :public SORT<T> //定义归并排序类 public继承SORT类 要继承SORT类中的成员函数模板 每个派生类的声明都要加上<T>
{
public:
void Merge(T a[],int first,int middle,int last,T temp[]);
void Sort(T a[], int n); //因为归并排序的形参与Sort(...)不一致,所以重新声明msort(...)来实现归并排序,再在Sort(...)调用
void msort(T a[],int first,int last,T temp[]);//归并排序,他要调用Merge函数才能完成排序
~MergeSort()
{
cout << "Release Merge Sort Object" << endl;//检验是否释放了MergeSort的对象
}
};
template<class T>
class SelectionSort :public SORT<T>
{
public:
void Sort(T a[],int n);
~SelectionSort()
{
cout<<"Release Selection Sort object"<<endl;//检验是否释放了SelectionSort的对象
}
};
template<class T>
class ExchangeSort:public SORT<T>
{
void Sort(T a[],int n);
~ExchangeSort()
{
cout<<"Release Exchange Sort object"<<endl;
}
};
template<class T>
class Factory //定义一个工厂类,将四种排序算法封装在该类中,要用时通过父类指针调用子类对象
{
public:
SORT<T> *pFather; //定义一个父类指针对象
T *datas; //定义Factory类数据成员
int size;
Factory(){ pFather = NULL ; datas = NULL ; } //定义构造函数将NULL赋值给*pFather和*datas
void Input(); //用户输入函数 具体注释在下面的定义中
void Show(); //打印排序后的数组
SORT<T> *creatSort(SORTTYPE type) //定义SORT类的返回指针类型的成员函数作为Factory的成员函数,使SORT类指针PFather能够调用之类对象
{
switch (type)
{
case Bubble:
return new BubbleSort<T>(); //返回子类的对象指针赋给父类指针即pFather
break;
case Insertion:
return new InsertionSort<T>(); //返回子类的对象指针赋给父类指针即pFather
break;
case Merge:
return new MergeSort<T>(); //返回子类的对象指针赋给父类指针即pFather
break;
case Selection:
return new SelectionSort<T>(); //返回子类的对象指针赋给父类指针即pFather
break;
case Exchange:
return new ExchangeSort<T>(); //返回子类的对象指针赋给父类指针即pFather
break;
default:
return new QuickSort<T>(); //输入0-6之外的数字时候默认返回快排类的指针
break;
}
}
void Run(SORTTYPE type)
{
pFather = creatSort(type); //creatSort函数返回子类对象的指针赋给父类指针即pFather
Input();
if (pFather != NULL) //判断子类的对象指针有没有成功赋值给*pFather
{
pFather->Sort(datas,size); //通过父类的pFather指针可以调用子类的Sort(...)函数
}
Show();
}
~Factory()
{
if (pFather != NULL) //释放前判空
{
delete pFather;
pFather = NULL; //释放对象后,立即把指针设置为NULL,防止产生“野指针”
cout << "Release the Factory object" << endl;
}
if (datas != NULL) //释放前判空
{
delete[]datas;
datas = NULL; //释放对象后,立即把指针设置为NULL,防止产生“野指针”
cout << "Release the data array" << endl;//检验是否释放了Factory 的对象
}
}
};
int main()
{
int choose;
char yes_no;
do{
Factory<double> *factory = new Factory<double>(); //在堆上申请一段内存。<推荐阅读C++动态分配内存>
menu();
cout << endl << "---Please select the sort to use (enter the digital 0-6): ";//让用户选择要用的排序
cin >> choose;
if (choose < 0 || choose >6)
{
choose = 2; //输入0-6以外的数字,默认使用快排
}
if (choose==0)
exit(0); //输入0 退出排序系统
factory->Run((SORTTYPE)choose);
if (factory != NULL) //在堆上申请的对象必须用户自己释放 释放前判空
{
cout << endl << "--------------------------------------------" << endl;//检验是否释放了Factory 的对象
delete factory;
factory = NULL; //释放对象后,立即把指针设置为NULL,防止产生“野指针”
cout << endl << "--------------------------------------------" << endl;
}
cout<<endl<<"Do you want to continue ? [y/n]"<<endl;//一次排序结束后,询问用户是否要继续使用该排序系统
do{
cin>>yes_no;
break;
}while(yes_no!='Y'&&yes_no!='y'&&yes_no!='N'&&yes_no!='n');//当用户输入非法字符时让用户循环输入直至合法为止
if(yes_no=='N'||yes_no=='n')//用户输入0退出系统
{
exit(0);
break;
}
}while(yes_no!='Y'||yes_no!='y');
return 0;
}
template <class T>
void BubbleSort<T>::Sort(T a[], int n)//冒泡排序定义
{
T temp;
for(int i=0;i<n-1;i++)
{
int count=0; //是否交换的标志
for(int j=0;j<n-1-i;j++)
{
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
count=1;
}
}
if(count==0) //若循环一轮结束后,没有发生交换,则说明该数据顺序已经排好,无需继续进行下去
break;
}
}
template <class T>
void QuickSort<T>::Sort(T a[], int n)
{
qsort(a, 0, n - 1);
}
template <class T>
void QuickSort<T>::qsort(T a[], int left, int right)//快速排序定义
{
if (left < right)
{
T key = a[left];
int i = left;
int j = right;
while (i < j)
{
while (i < j&&a[j] >= key)
{
j--;
}
a[i] = a[j];
while (i < j&&a[i] <= key)
{
i++;
}
a[j] = a[i];
}
a[i] = key;
qsort(a, left, i - 1); //调用自身
qsort(a, i + 1, right);//调用自身
}
}
template <class T>
void InsertionSort<T>::Sort(T a[], int n) //插入排序
{
int temp;
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j>0;j--)
{
if(a[j]<a[j-1])
{
temp=a[j-1];
a[j-1]=a[j];
a[j]=temp;
}
else
break;
}
}
}
template <class T>
void MergeSort<T>::Merge(T a[],int first,int middle,int last,T temp[])
{
int i = first;
int m = middle;
int j = middle+1;
int n = last;
int k = 0;
while(i<=m && j<=n)
{
if(a[i] <= a[j])
{
temp[k] = a[i];
k++;
i++;
}
else
{
temp[k] = a[j];
k++;
j++;
}
}
while(i<=m)
{
temp[k] = a[i];
k++;
i++;
}
while(j<=n)
{
temp[k] = a[j];
k++;
j++;
}
for(int i=0;i<k;i++)
{
a[first + i] = temp[i];
}
}
template <class T>
void MergeSort<T>::msort(T a[],int first,int last,T temp[])//归并排序
{
if(first < last)
{
int middle = (first + last)/2;
msort(a,first,middle,temp);//左半部分排好序
msort(a,middle+1,last,temp);//右半部分排好序
Merge(a,first,middle,last,temp); //合并左右部分
}
}
template <class T>
void MergeSort<T>::Sort(T a[], int n)
{
T temp[n];
msort(a,0,n-1,temp);
}
template <class T>
void SelectionSort<T>::Sort(T a[],int n) //选择排序
{
T temp;
int k;
for(int i=0;i<n-1;i++)
{
k=i;
for(int j=i+1;j<n;j++)
{
if(a[j]<a[k])
k=j;
}
if(k!=i)
{
temp=a[k];
a[k]=a[i];
a[i]=temp;
}
}
}
template <class T>
void ExchangeSort<T>::Sort(T a[],int n) //交换排序
{
T temp;
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
if(a[j]<a[i])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
}
void menu()
{
cout <<endl<<"***********************************************************************" << endl;
cout << " -----ORDERING SYSTEM-----" << endl << endl;
cout << "--------NO.1 Bubble sort(1)-------- " << endl;
cout << "--------NO.2 Quick sort(2)-------- " << endl;
cout << "--------NO.3 Insertion sort(3)-------- " << endl;
cout << "--------NO.4 Merge sort(4)-------- " << endl;
cout << "--------NO.5 Selection sort(5)-------- " << endl;
cout << "--------NO.6 Exchange sort(6)-------- " << endl;
cout << "--------Zero Exit the system(0)-------- " <<endl;
cout <<endl<<"***********************************************************************" << endl;
}
template <class T>
void Factory<T>:: Input()
{
size = 0;
cout << "Input Datas Size: " ;//提示用户输入数组长度
cin >> size;
cout << "Input the datas: ";//提示用户输入待排序数组
if (datas != NULL)
{
delete[]datas; //在堆上申请的对象必须用户自己释放 释放前判空
datas = NULL; //释放对象后,立即把指针设置为NULL,防止产生“野指针”
}
datas = new T[size];//在堆上申请内存 <推荐阅读C++动态分配内存>
if (datas == NULL)//判断内存分配是否成功
{
cout << "Get Memoery Failed, exit" << endl;
exit(0);
}
int i = 0;
while (i < size)
{
cin >> datas[i++];//相当于 cin>>datas[i];i++;
}
}
template <class T>
void Factory<T>::Show()
{
cout << "The result is as below:" << endl;
for (int j = 0; j < size; j++)
cout << datas[j] << " ";
}
功能实现:
1、冒泡排序:
2、快速排序:
3、直接插入排序:
4、归并排序: