排序算法 快排 堆排 选择 插入 希尔 归并

最古老的算法莫过于对什么东西进行排序,现对于基本的排序算法 进行下总结,主要参考书籍 《算法导论 第二版》 

1.1 插入排序简介

算法简单化类似于玩扑克游戏,在每次抓牌的过程中,总是按照一定的顺序将牌弄好(将小牌从左至右依次排好),当本次抓的牌比手中已有的牌的某一张小,就将它插入那张牌的前面,所以插入排序就类似于这样的一个过程。
对于 给定的输入:A = <5,2,4,6,1,3> 对应于相应的输出 A' = <1,2,3,4,5,6>

1.2 C++源码Demo

#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;

void insertion_sort(int *a,int len){
    int i,j;
    for(j=1;j<len;j++){     //模拟每次抓牌,插牌的过程
        int key = a[j];
        i = j-1;
        while(i>=0 && a[i]>key){
            a[i+1]=a[i];
            i--;
        }
        a[i+1] = key;   //对应于上面的i--
    }
}
int main()
{
    int a[6] = {5,2,6,1,3,4};
    int _len = sizeof(a)/sizeof(int);

    insertion_sort(a,_len); //函数调用

    /*
    **输出排好顺序的数组,同时里面还有包含了格式化的输出 setw 对应的头文件是#include <iomanip>
    */

    int i;
    for(i=0;i<_len;i++)
        cout<<setw(5)<<a[i];
    cout<<endl;
    return 0;

}

2. 希尔排序

2.1 希尔排序简介

希尔排序先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。希尔排序源于插入排序,同时也是对插入排序的改进。希尔排序主要本质就是将分组之后进行插入排序,只是引入了个缩减量。

2.2  希尔排序C++代码

#include <iostream>
using namespace std;

void shell(int *a,int step){
    int d,i,j,key;
    /*
    **对数据进行分组,在对分组进行插入排序,模拟插入排序过程
    */
    for(d=step/2;d>=1;d/=2){
        for(i=d;i<step;i++){
            key = a[i];
            for(j=i-d;(j>=0&&a[j]>key);j=j-d){
                a[j+d] = a[j];
            }
            a[j+d] = key;
        }
    }
}
int main()
{
    int a[10] = {49,38,65,97,26,13,27,49,55,4};
    int len = sizeof(a)/sizeof(int);
    shell(a,len);
    int i;
    for(i=0;i<len;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}

3 选择排序

3.1 选择排序简介

选择排序主要就是每次的选择都将最大(或最小)的放在相应的位置上面。

3.2 选择排序C++代码

#include <iostream>

using namespace std;
void select_sort(int *a,int len){
    int i,j,pos;
    for(i=0;i<len;i++){
        pos = i;
        for(j=i+1;j<len;j++){
            if(a[j]<a[pos]){
                pos = j;    //记录每次选择的最小位置
            }
        }
        swap(a[pos],a[i]);
    }
}
int main()
{

    int a[5] = {10,21,2,3,5};
    int _len = sizeof(a)/sizeof(int);

    select_sort(a,_len);    //函数调用
    int i=0;
    for(;i<_len;i++)
        cout<<"a["<<i<<"]="<<a[i]<<" ";
    cout<<endl;

    return 0;
}

4 冒泡排序

4.1 冒泡排序简介

冒泡排序主要思想类似于水泡,较重的水泡沉下去,较轻的水泡浮上来。

4.2 冒泡排序C++代码

#include <iostream>
using namespace std;

void maopao_sort(int *a,int len){
    int i,j;
    for(i=0;i<len;i++){
        /*
        **每轮比较完之后,
        **最大的都会是在最下面
        **len-i-1 比较几轮,减少几次
        */
        for(j=0;j<len-i-1;j++){
            if(a[j]>a[j+1])
                swap(a[j],a[j+1]);
        }
    }
}
int main()
{

    int a[5] = {10,21,2,3,5};
    int _len = sizeof(a)/sizeof(int);

    maopao_sort(a,_len);    //函数调用

    int i=0;
    for(;i<_len;i++)
        cout<<"a["<<i<<"]="<<a[i]<<" ";
    cout<<endl;

    return 0;
}

5.归并排序

5.1 归并排序简介

归并 排序是建立在归并操作上的一种有效的 排序算法。该算法是采用 分治法(Divide and Conquer)的一个非常典型的应用。值得注意的是归并排序是一种 稳定的排序方法。 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序 ,称为二路 归并
归并操作的工作原理如下: 第一步:申请空间,使其大小为两个已经 排序 序列之和,该空间用来存放合并后的序列
第二步:设定两个 指针 ,最初位置分别为两个已经 排序 序列的起始位置
第三步:比较两个 指针 所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾 将另一序列剩下的所有元素直接复制到合并序列尾

5.2 归并排序C++代码

#include <iostream>
#include <climits>
#include <cmath>
using namespace std;
/*
**分割几部分 p代表开始位置,q为中间位置
**r为结束位置
*/
void merge(int *a,int p,int q,int r){
    int n1 = q-p+1;
    int n2 = r-q;
    int l[n1+1],R[n2+1];    //二路归并

    for(int i=1;i<=n1;i++)
        l[i] = a[p+i-1];    //越界问题
    for(int j=1;j<=n2;j++)
        R[j] = a[q+j];
                            //结尾标志,带哨兵
    l[n1+1] = INT_MAX;
    R[n2+1] = INT_MAX;

    int i=1,j=1;        //从一开始
    for(int k=p;k<=r;k++){
        if(l[i]<R[j]){
              a[k] = l[i];
              i++;
        }
        else{
            a[k] = R[j];
            j++;
        }
    }
}
void merge_sort(int *a,int p,int r){
    int q;
    if(p<r){
        q = floor((p+r)/2);
        merge_sort(a,p,q);
        merge_sort(a,q+1,r);
        merge(a,p,q,r);
    }
}
int main()
{
    int a[5] = {10,21,2,3,5};
    int _len = sizeof(a)/sizeof(int);

    merge_sort(a,0,_len-1); //函数调用

    int i=0;
    for(;i<_len;i++)
        cout<<"a["<<i<<"]="<<a[i]<<" ";
    cout<<endl;
    return 0;
}

6. 快速排序

6.1 快速排序简介(传统快排)

快速排序是对冒泡的改进,假使第一个元素作为标记元素,采用快排使得,分为俩部分,一部分比这个标记元素要小,而另一部分要比这个标记元素要大,同时迭代在各自的部分之内寻找新的子部分,直至排好顺序。
示例代码采取第一个元素作为标记元素:

6.2 快速排序C++源码

#include <iostream>
using namespace std;

int Partion(int *a,int p,int r){
    int key,i,j;
    key = a[p];
    i=p;
    for(j=p+1;j<=r;j++){
        if(a[j]<key){
            i++;
            swap(a[i],a[j]);
        }
        swap(a[i],a[p]);
    }
    return i+1;     //越界考虑
}

void quick_sort(int *a,int p,int r){
    if(p<r){
        int q = Partion(a,p,r);
        quick_sort(a,p,q-1);
        quick_sort(a,q+1,r);
    }
}
int main()
{
    int a[5] = {10,21,2,3,5};
    int _len = sizeof(a)/sizeof(int);

    quick_sort(a,0,_len-1); //函数调用

    int i=0;
    for(;i<_len;i++)
        cout<<"a["<<i<<"]="<<a[i]<<" ";
    cout<<endl;
    return 0;
}

7. 计数排序

7.1 计数排序简介

计数排序是一种非比较的排序算法,而是根据统计次数和相应的位置进行存放数据,适用于数据中的最大值(k)不是远远大于数据个数(n),在一定的范围内此排序算法较快。

7.2 计数排序c++代码

#include <iostream>
using namespace std;

void counting_sort(int *a,int len,int k){
    int b[len];
    int c[k+1];
    for(int i=0;i<=k;i++){
        c[i] = 0;
    }
    //计数 每个数据出现次数
    for(int j=0;j<len;j++){
        c[a[j]] =  c[a[j]]+1;
    }
    //位置 记录位置
    for(int i=1;i<=k;i++){
        c[i] = c[i]+c[i-1];
    }

    for(int j=len-1;j>=0;j--){
        b[c[a[j]]] = a[j];
        c[a[j]] = c[a[j]]-1;
    }

    int i=1;
    for(;i<=len;i++)
        cout<<"b["<<i<<"]="<<b[i]<<" ";
    cout<<endl;
}
int main()
{
    int a[5] = {2,3,3,1,4};
    int _len = sizeof(a)/sizeof(int);
    int k=4; //(a数据中的最大值 直接用来表示了 类似k=max(...)情况)

    counting_sort(a,_len,k); //函数调用

    return 0;
}

8. 堆排序

8.1 堆排序简介

堆数据结构是一组数组对象,可以被视为是一棵完全二叉树,每一层都是填满的,出了最后一层,但是最后一层也是从左向右填充,length(A)是数组中元素的个数,而heap-size(A)是存放在A中的堆元素个数,一般heap-size(A)<= lenght(A),树的根为A[1],给定某个节点下标i,父节点Parent(i),左孩子left(i),右孩子(i)表示为:
Parent(i)return floor(i/2); left(i) return 2*i; right(i) return 2*i+1;
堆的数据结构 包括大根堆 ,小根堆。大根堆,顾名思义根的值要大于孩子的值,而小根堆则是根的值 则要小于孩子的值,在堆的排序算法中,此文采用的是大根堆。
堆排序的步骤:
1.对于输入数组,和下标组成大根堆
2.建堆
3排序

8.2 堆排序C++代码

#include <iostream>
#include <cmath>
using namespace std;
//父节点
int Parent(int i){
    return floor(i/2);
 }
 //左孩子
int heap_Left(int i){
    return 2*i;
}
//右孩子
int heap_Right(int i){
    return 2*i+1;
}
//最大堆
void max_heapify(int *a,int i,int heap_size){
    int l = heap_Left(i);
    int r = heap_Right(i);
    int largest;
    if(l<=heap_size-1 && a[l]>a[i])
        largest = l;
    else
        largest = i;
    if(r<=heap_size-1 && a[r]>a[largest])
        largest = r;
    if(largest != i){
        swap(a[i],a[largest]);
        max_heapify(a,largest,heap_size);
    }
}
//建堆
void build_heap(int *a,int len){
    for(int i=floor(len/2);i>=0;i--)
        max_heapify(a,i,len);
}
//堆排序
void heap_sort(int *a,int len){
    build_heap(a,len);
    for(int i=len-1;i>=1;i--){
        swap(a[i],a[0]);
        len--;
        max_heapify(a,0,len);
    }
}
int main()
{
    int a[6] = {10,21,2,3,5,37};
    int _len = sizeof(a)/sizeof(int);

    heap_sort(a,_len); //函数调用

    int i=0;
    for(;i<_len;i++)
        cout<<"a["<<i<<"]="<<a[i]<<" ";
    cout<<endl;

    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值