C++ 排序

C++实现。

  1. 冒泡排序,稳定
  2. 选择排序,不稳定,比如,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
  3. 插入排序,稳定
  4. 希尔排序 不稳定
  5. 归并排序,稳定
  6. 快速排序
    在这里插入图片描述
/*主要是冒泡排序,快速排序,插入排序,希尔排序,选择排序,堆排序,归并排序*/
//冒泡排序
//#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来保存之前交换的中间位置。
}
*/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值