C++实现。
- 冒泡排序,稳定
- 选择排序,不稳定,比如,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
- 插入排序,稳定
- 希尔排序 不稳定
- 归并排序,稳定
- 快速排序
/*主要是冒泡排序,快速排序,插入排序,希尔排序,选择排序,堆排序,归并排序*/
//冒泡排序
//#include <iostream>
//#include <vector>
//using namespace std;
//
//int main()
//{
cin >> n;
vector<int> nums(9)={3, 2, -3, 1, 2, 4, 5, 5, 6};这种用法不允许
// int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
// vector<int> nums(temp,temp+9);
// int len = nums.size();
// int flag = true;
// for(int i = 0;i < len-1;++i){
// for(int j = 0;j < len -i -1;j++){//j应该从0开始,这里刚才出错了
// if(nums[j] > nums[j+1]){
// swap(nums[j],nums[j+1]);
// flag = false;
// }
// }
// if(flag == true){
// break;
// }
// flag = true;//不加这行的话,还是会跑len轮,这里开始忘加了。
//
// }
// cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
//
// return 0;
//}
//选择排序
//#include <iostream>
//#include <vector>
//using namespace std;
//
//int main()
//{
int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
// int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};
// vector<int> nums(temp,temp+9);
// int len = nums.size();
// int flag = true;
// int minal;
// for(int i = 0,j;i < len-1;++i){
minal = nums[i];还是保存坐标比较好,让minal=nums[i]的话,下面那个循环,最后swap(num[i],num[j])不对哈,因为j肯定就是len-1
// minal = i;
// for(j = i+1;j < len;j++){
// if(nums[minal] > nums[j]){
// minal = j;
// flag = false;
// }
if(flag == true){
break;
}
// flag = true;//不应该加flag,因为最好的时间复杂度也是O(n2)
// }
// swap(nums[i],nums[minal]);
//
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
//
// }
//
// cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
// return 0;
//}
//插入排序
//#include <iostream>
//#include <vector>
//using namespace std;
//
//int main()
//{
// int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
// vector<int> nums(temp,temp+9);
// int len = nums.size();
// int temp1;
// for(int i = 1,j;i < len;++i){
// temp1 = nums[i];
// for(j = i-1;j>=0;j--){
if(nums[i] < nums[j]){这里出问题了,nums数组第i个位置不是原来的数了,不能这样,你影响他了,所以应该弄一个中间变量
// if(temp1 < nums[j]){
// nums[j+1] = nums[j];
// }else{
// break;
// }
// }
// nums[j+1]=temp1;
// }
//
// cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
// return 0;
//}
//希尔排序这里我没想好1.选择增量:gap = length / 2,缩小增量:gap = gap /2 ;怎么处理。看了之后我知道了。就把类似i--换成gap=gap/2
//2.原本的插入排序第一个for循环也是从第2个元素开始的,那这个也应该如此。这个的第二个元素应该是nums[gap],原本的是nums[1]
//#include <iostream>
//#include <vector>
//using namespace std;
//
//int main()
//{
int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
// int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};
// vector<int> nums(temp,temp+9);
// int len = nums.size();
// int temp1;
// for(int i = len/2;i != 0;i/=2){
// cout << i << endl;
// for(int j = i,k;j<len;j+=i){
// temp1 = nums[j];
// for(k = j-i;k>=0;k-=i){
// if(temp1 < nums[k]){
// nums[k+i] = nums[k];
// }else{
// break;
// }
// }
// nums[k+i] = temp1;
// }
// }
cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
// return 0;
//}
//做出来了,希尔排序就是将插入排序每次加1变为从len/2,然后再除2,最后得到间隔为1即可。
//归并排序 第一遍的做法
//#include <iostream>
//#include <vector>
//using namespace std;
//
//int main()
//{
// int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
// vector<int> nums(temp,temp+9);
// vector<int> res(nums);
// int len = nums.size();
// int temp1;
// guibing(0,len);
// return 0;
//}
//
//void guibing(int start,int duanchang)
//{
// if(duanchang <= 1){
// return;
// }
// guibing(start,duanchang/2);
// guibing(start+duanchang/2,duanchang/2);
// //这两个执行完就是默认里面两小段已经排序完了
// //但我没考虑好怎么处理边界。奇数的情况下咋办。
// int i = start,j = start+duanchang/2,temp=start;
// for(int k = start;k<=start+duanchang;k++){//一开始我这里用for循环,没用while,然后下面还得多用两个if判断条件,while(i<=start+midle&&j<start+duanchang)就不用了
// if(nums[i]<nums[j]){
// b[temp++] = nums[i++];
// }else{
// b[temp++]= nums[j++];
// }
// if(i==start+duanchang/2+1){
// break;
// }
// if(j==start+duanchang){
// break;
// }
// }
//}
/*看了点东西的第二遍做法
有两个问题
1.我在两个guibing函数后面那一串长的操作没弄成函数
2.分成两段,第二段起始应该是midle+1
3.// //这两个执行完就是默认里面两小段已经排序完了
// //但我没考虑好怎么处理边界。奇数的情况下咋办。
当时对这个问题没想好怎么处理,现在我知道了。弄两个while就可以了,本来下面只打算弄一个while的。
同时我发现类似这种像指针递归,两个标志递进的用while比较方便。*/
//#include <iostream>
//#include <vector>
//using namespace std;
//
int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
//int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};
//vector<int> nums(temp,temp+9);
vector<int> res(nums);
//void guibing(int start,int duanchang);
//void mergeguibing(int start,int duanchang);
//int main()
//{
//
// int len = nums.size();
// int temp1;
// guibing(0,len);
cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
// return 0;
//}
//#我用段长是有问题的,如果段长为奇数,duanchang/2=偶数。 guibing(start,middle); guibing(middle,duanchang/2);就会少计算一个数。
//void guibing(int start,int duanchang)
//{
// if(duanchang <= 1){
// return;
// }
// int middle = duanchang/2;
// guibing(start,middle);
// guibing(middle,duanchang/2);
// mergeguibing(start,duanchang);
// //这两个执行完就是默认里面两小段已经排序完了
// //但我没考虑好怎么处理边界。奇数的情况下咋办。
//
//}
//void mergeguibing(int start,int duanchang)
//{
// int i = start,middle = duanchang/2;
// int j = middle,temp=0;
// int* tmp = new int[duanchang];
// while(i<middle&&j<duanchang){//这里刚才出错了我写的while(i<=start+middle&&j<=start+duanhang)、想错了,这样多弄了。
// if(nums[i]<nums[j]){
// tmp[temp++] = nums[i++];
// }else{
// tmp[temp++]= nums[j++];
// }
// }
// while(i<middle){
res[temp++]=nums[i++];.这里也错了,我如果不将nums数组改变的话,以后合并的过程中比较的也还是没有排序的,不对,所以应该弄一个中间数组。
// tmp[temp++] = nums[i++];
// }
// while(j<duanchang){
res[temp++]=nums[j++];
// tmp[temp++]= nums[j++];
// }
// for(i=start,temp=0;i<duanchang;i++){
// nums[i] = tmp[temp++];
// }
// delete []tmp;
//}
/*上面这样就对了。
1.midle我老是弄成start+middle不是这样的。可以让middle=start+duanchang/2
2.知乎上的代码https://zhuanlan.zhihu.com/p/74820690跟我的思路是一样的,但人家传递的函数参数个数,意义不同。我传的是数组开始+数组总长度
3.一定要考虑好两个分段的起始数是多少,该不该+1这种。
4.代码行数多弄成一个函数。
也不对,int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};这组测试用例就没通过。
//第三次归并排序*/
//#include <iostream>
//#include <vector>
//using namespace std;
//
int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};///下面的程序通过了
//int temp[9] = {98, 22, -3, -69, 2, -6, 666, 31, 72};
//vector<int> nums(temp,temp+9);
vector<int> res(nums);
//void guibing(int start,int endd);
//void mergeguibing(int start,int endd);
//int main()
//{
//
// int len = nums.size();
// int temp1;
// guibing(0,len-1);
cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
// return 0;
//}
#我用段长是有问题的,如果段长为奇数,duanchang/2=偶数。 guibing(start,middle); guibing(middle,duanchang/2);就会少计算一个数。
//void guibing(int start,int endd)
//{
// if(start>=endd){
// return;
// }
// int banchang = (endd-start+1)/2;
// int middle = start+banchang;
// guibing(start,middle-1);
// guibing(middle,endd);
// mergeguibing(start,endd);
// //这两个执行完就是默认里面两小段已经排序完了
// //但我没考虑好怎么处理边界。奇数的情况下咋办。
//
//}
//void mergeguibing(int start,int endd)
//{
// int i = start,banchang = (endd-start+1)/2;
// int middle = start+banchang;;
// int j = middle,temp=0;
// int* tmp = new int[endd-start+1];
// while(i<middle&&j<=endd){//这里刚才出错了我写的while(i<=start+middle&&j<=start+duanhang)、想错了,这样多弄了。
// if(nums[i]<nums[j]){
// tmp[temp++] = nums[i++];
// }else{
// tmp[temp++]= nums[j++];
// }
// }
// while(i<=middle){
res[temp++]=nums[i++];.这里也错了,我如果不将nums数组改变的话,以后合并的过程中比较的也还是没有排序的,不对,所以应该弄一个中间数组。
// tmp[temp++] = nums[i++];
// }
// while(j<=endd){
res[temp++]=nums[j++];
// tmp[temp++]= nums[j++];
// }
// for(i=start,temp=0;i<=endd;i++){
// nums[i] = tmp[temp++];
// }
// delete []tmp;
//}
/*上面这个归并排序就是最终对了的版本,这提醒我们
1.还是得用(start,end)这种,用(start,duanchang)这种的话,奇数的不好处理
2.当guibing里面用的是 总长度 = (endd-start+1)。我们可以自己试一试,弄几个数试出来。
guibing(start,middle-1);
guibing(middle,endd);
你看这里分别是(start,middle-1),(middle,endd)
然后你在下面的mergeguibing中也要让i=start然后i<middle而不能是i<=middle因为前面也是guibing(start,middle-1),同理j<=endd;
我是如何弄出 guibing(start,middle-1);guibing(middle,endd);的呢
我找了四个数的话,我发现guibing(start,middle),guibing(middle+1,endd)的话,会使得前面有三个数,后面只有一个数,不对,调整一下。
*/
//快速排序
//#include <iostream>
//#include <vector>
//using namespace std;
int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
//int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};
//void quickSort(int start,int endd);
//vector<int> nums(temp,temp+9);
//
//int main()
//{
// int len = nums.size();
// int temp1;
// quickSort(0,len-1);
cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
// return 0;
//}
//void quickSort(int start,int endd)
//{
// if(start >= endd){
// return;
// }
// int i,j;
// int flag = nums[start],station=start;
// for(i = start,j=endd;i <= j;)
// {
// while(nums[i] >= flag)
// {
// i++;
// }
// if(nums[i] < flag){
// swap(nums[i],nums[station]);
// station = i++;
// }
// while((nums[j] >= flag) && (j>=i))
// {
// j--;
// }
// if(nums[j] < flag){
// swap(nums[j],nums[station]);
// station = j--;
// }
//
// }
// quickSort(start,i-1);
// quickSort(i,endd);
//}
/*上面这个快排有问题,我原来的想法是从左向右找比他小的,然后从右向左也找比他小的,但这样然后交换,但这样不能达到一个左边的数都小于flag同时右边的数都大于flag
的效果,我在纸上弄了一下,应该从左向右找比他大的,然后从右向左也找比他小的,然后最后交换flag那个位置和最后两个指针相遇的那个位置。*/
//#include <iostream>
//#include <vector>
//using namespace std;
int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
//int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};
//void quickSort(int start,int endd);
//vector<int> nums(temp,temp+9);
//
//int main()
//{
// int len = nums.size();
// int temp1;
// quickSort(0,len-1);
cout<<"最后的结果"<<endl;
// for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
// {
// cout << *iter<<" ";
// }
// cout << endl;
// return 0;
//}
//void quickSort(int start,int endd)
//{
// if(start >= endd){
// return;
// }
// int i,j;
// int flag = nums[start],station=start;
// for(i = start,j=endd;i != j;)
// {
// while(nums[i] <= flag && (j>i))
// {
// i++;
// }
if(nums[i] > flag){
swap(nums[i],nums[station]);
station = i++;
}
// while((nums[j] >= flag) && (j>i))
// {
// j--;
// }
// if(nums[j] < flag){
// swap(nums[j],nums[station]);
// station = j--;
// }
//
// }
// quickSort(start,i-1);
// quickSort(i,endd);
//}
/*记一下思路,交换两次,先换找到的j与station,再换station与i
特殊情况 3,-1,-3,-2,4
此时不能让i = 4的位置,因为就不好换了所以设置一下限制i < j
j= -2的位置。i就是start的位置,自己换自己不影响
我想不出怎么处理。然后我去看了下正确答案,我跟他区别是一个顺序和一个指针和一个判断条件*/
#include <iostream>
#include <vector>
using namespace std;
//int temp[9] = {3, 2, -3, 1, 2, 4, 5, 5, 6};
//int temp[9] = {3, 22, -3, 1, 2, -6, 9, 31, 6};
int temp[10] = {6,1,2,7,9,3,4,5,10,8};
void quickSort(int start,int endd);
vector<int> nums(temp,temp+10);
int main()
{
int len = nums.size();
int temp1;
quickSort(0,len-1);
// cout<<"最后的结果"<<endl;
for(vector<int>::iterator iter = nums.begin();iter != nums.end();iter++)
{
cout << *iter<<" ";
}
cout << endl;
return 0;
}
void quickSort(int start,int endd)
{
if(start >= endd){
return;
}
int i,j;
int flag = nums[start],station=start;
for(i = start,j=endd;i != j;)
{
while((nums[j] >= flag) && (j>i))
{
j--;
}
if(i < j)
{
//station = i++;
// swap(nums[station],nums[j]);
nums[i++] = nums[j];
}
while(nums[i] <= flag && (j>i))
{
i++;
}
if(i < j){
nums[j--] = nums[i];
// station = j--;
// swap(nums[j],nums[station]);
}
}
nums[i] = flag;
quickSort(start,i-1);
quickSort(i+1,endd);
}
/*上面这个快速排序是最终正确的版本,有几个问题我没弄好弄对
1.快速排序是通过一次排序将要排序的数据分成两部分,其中一部分所有数据比flag小,另一部分所有数据比flag大,所以一次排序之后,中间那个flag就不用排了
所以最后是quickSort(start,i-1),quickSort(i+1,end) 位置i那个不需要进行排序了
2.首先从右向左找,然后从左向右找
3.这种循环一般都用while比较方便所以一般将for(i = start,j=endd;i != j;)改为while(i != j)
4.一开始在从左向右或者从右向左跑一轮之后,下面的if判断条件我写的是类似if(nums[j] < flag)不对哈,这个条件是肯定满足的。从左向右的过程中
这个条件是肯定满足的,停下你要判断是否还满足(i < j)这个条件。
5.满足if条件后,应该怎么交换。我之前 swap(nums[i],nums[station]); station = i++;这种也对,其实这个station没必要用
完全可以if(i<j)
{
swap(nums[i++],num[j]);我之前用了一个station来保存之前交换的中间位置。
}
*/