排序算法代码详解

#include <iostream>
using namespace std;

void print(int a[], int len)
{
        for(int i = 0; i < len; i++)
        cout << a[i] << " ";
        cout << endl;
}

void swap(int &a, int &b)
{
    if( a > b)
    {
        int t = a;
        a = b;
        b = t;
    }
}

void bubble_sort(int a[], int len)
{
    //冒泡排序
    int exchange = 0;        //设置标记
    for(int i = 0; i < len - 1; i++)    //总共有 n-1 次排序
    {
        exchange = 0;    //每次把标记置 0
        for(int j = len - 2; j >= i; j--)  //从后往前比较
        {
            if(a[j] > a[j+1])    //比较大小,交换数据
            {
                int tmp = a[j];  
                a[j] = a[j+1];
                a[j+1] = tmp;
                exchange = 1;     //发生数据交换,标记置1
            }
        }
        if(exchange != 1)    //标记不为1,跳过这次循环
                break;
    }
}

void select_sort(int a[], int len)
{
    //简单选择排序,每次找到最小的那个数和第一个数交换位置
    int i, j, tmp, min;
    for(i = 0; i < len -1 ;i++)  // n-1 次 循环
    {
        tmp = a[i];    //记录每次第一个元素的值和下标
        min = i;
        for(j = i+1; j < len; j++)
        {
            if(a[j] < tmp)   //如果当前位置的值小于第一个元素的值
            {
                tmp = a[j];   //把当前元素的值和下标记录下来
                min = j;
            }  
        }
        if(min != i)   //如果flag标记发生变化,表示有元素的值比第一个数小
        {
            a[min] = a[i];  //交换两个数的值
            a[i] = tmp;    
        }
    }
}

void insert_sort(int a[], int len)
{
    //直接插入排序:把第一个数当成一个有序数组,后面的数一个一个有序的插入的数组中
    int i, j, tmp;
    for(i = 1; i < len; i++)
    {    
        tmp = a[i];   //tmp用来记录要插入的数的值

        //满足条件,往后挪。当 tmp > a[j] 小,tmp 放在 a[j] 后面 
        for(j = i-1; j >= 0 && tmp < a[j]; j--) 
            a[j+1] = a[j];  
        a[j+1] = tmp;       
    }
}

void shell_sort(int a[], int len)
{
    int d = len;
    while(d > 1)
    {
        d = (d + 1)/2;  //设置增量
        for(int i = 0; i < len -d; i++) 
        {
            if(a[i] > a[i+d])  //交换相隔距离 d 的两个数的值
            {
                int tmp = a[i];
                a[i] = a[i+d];
                a[i+d] = tmp;
            }
        }
    }
}

void heap_adjust(int a[], int len, int index)
{
    int left = 2*index + 1;    //父节点左孩子下标
    int right = 2*index + 2;   //父节点有孩子下标
    int maxindex = index;      //令最大值的下标为当前父节点下标
    if(left < len && a[left] > a[maxindex])      //在数组范围内且左孩子的值大于父节点的值
        maxindex = left;                         //最大值下标变为左孩子下标
    if(right < len && a[right] > a[maxindex])    //在数组范围内且右孩子的值大于父节点的值
        maxindex = right;                        //最大值下标变为右孩子下标
    if(maxindex != index)                        //当最大值下标更新
    {
        swap(a[maxindex], a[index]);             //交换最大值下标对应的值和父节点的值
        heap_adjust(a, len, maxindex);           //递归调整其他不满足堆性质的部分
    }
}

void heap_sort(int a[], int len)
{
    int i;            //最后一个非叶子节点的下标为 len/2 -1 
    for(i = len/2 -1; i >= 0; i--)    //对每一个父节点进行调整,使堆变成大顶堆(从最后一个父节点开始) 非叶子结点即父节点
    {
        heap_adjust(a, len, i);       // i 为当前父节点下标
    }
    for(i = len -1; i > 0; i--)       //从后往前,保存最大的数
    {
        swap(a[0], a[i]);             //把经过调整的大顶堆的最大值和最后一个元素互换位置,放到数组末尾
        heap_adjust(a, i, 0);          //将剩下的部分继续进行堆排序
    }
}

void merge(int a[], int begin, int middle, int end)
{
    int i, j, k, leftlen, rightlen;
    leftlen = middle - begin + 1;    //左区间元素个数
    rightlen = end - middle;         //右区间元素个数

    int *L = new int(leftlen);      //申请两个数组用来分别存放 左区间 和  右区间 的元素
    int *R = new int(rightlen);

    for(i = 0, k = begin; i < leftlen; i++, k++)   //对 数组 L 进行赋值
    {
        L[i] = a[k];
    }

    for(i = 0, k = middle + 1; i < rightlen; i++, k++)   //对 数组 R 进行赋值
    { 
        R[i] = a[k];
    }

    for(k = begin, i = 0, j = 0; i < leftlen && j < rightlen; k++)   //对原数组进行重新排序
    {
        if(L[i] < R[j])       //左区间当前下标的值小于右区间的值
        {
            a[k] = L[i];      //数组当前下标元素的值为左区间的值
            i++;              //左区间下标加1
        }
        else                  //反之
        {
            a[k] = R[j];      //数组当前下标元素的值为右区间的值
            j++;              //右区间下标加1
        }
    }

    if(i < leftlen)          //这两个 if 语句 是将 左区间 和 右区间 归并剩下的数据 放到数组的最后面
    {
        for(j = i; j < leftlen; j++, k++)  // j = i  属于习惯问题    可以写成  for (; i < n1; i++, k++)
        {
            a[k] = L[j]; 
        }
    }

    if(j < rightlen)
    {
        for(i = j; i < rightlen; i++, k++)  // i = j  属于习惯问题    可以写成  for (; j < n2; j++, k++)
        {
            a[k] = R[i];
        }
    }

    delete [] L;
    delete [] R;
}

void merge_sort(int a[], int begin, int end)
{
    if(begin < end)
    {
        int middle  = (begin + end) / 2;   //定义分界点,将数组分为两部分
        merge_sort(a, begin, middle);      //对左区间 [begin, middle] 递归做归并排序
        merge_sort(a, middle + 1, end);    //对右区间 [middle + 1, end] 递归做归并排序
        merge(a, begin, middle, end);      //组合,将两个有序的区块合并成一个有序的区块
    }
}

void quick_sort(int a[], int begin, int end)
{
    if(begin < end)
    {
        int pivot = a[begin];      //将数组第一个数作为比较关键字,保存下来
        int i = begin;             //从前往后
        int j = end;               //从后往前
        while(i < j)
        {
            while(i < j && a[j] >= pivot)   // i < j 且 a[j] 大于等于 关键字 时
                j--;                        // j--, 下标向前挪一位   
            if(i < j && a[j] < pivot)       // i < j 且 a[j] 小于 关键字 时
                a[i++] = a[j];              // 令 a[i] = a[j]  a++ 下标向后挪一位
            while(i < j && a[i] <= pivot)   // i < j 且 a[i] 小于等于 关键字 时
                i++;                        // i++, 下标向后挪一位
            if(i < j && a[i] > pivot)       // i < j 且 a[i] 大于 关键字 时
                a[j--] = a[i];              // 令 a[j] = a[i]  j-- 下标向前挪一位
        }
        a[i] = pivot;
        quick_sort(a, begin, i - 1);
        quick_sort(a, i+1, end);
    }
}

int main()
{
    int a[] = {7,1,3,2,5,6,4,9,8};
    int len  = sizeof(a)/sizeof(a[0]);

    cout << "排序前" << endl;
    print(a, len);

    // 冒泡排序:两辆比较关键字,反序则交换
    // cout << "冒泡排序" << endl;
    // bubble_sort(a, len);
    // print(a, len);

    // 简单选择排序:通过(n - i)次关键字间的比较, 从(n - i - 1)个记录中选择关键字最小的记录,并和第 i 个记录交换位置
    // cout << "选择排序" << endl;
    // select_sort(a, len);
    // print(a, len);

    // 直接插入排序:将第一个数视为有序数组,把后面每一个数都有序插入到数组中,使整个序列有序
    // cout << "直接插入排序" << endl;
    // insert_sort(a, len);
    // print(a, len);

    // 希尔排序:把相距某一个增量 d( d = len; d = (d+1)/ 2;) 的记录组成子序列,然后在子序列内进行直接插入排序,再对全体记录进行一次直接插入排序
    // cout << "Shell排序" << endl;
    // shell_sort(a, len);
    // print(a, len);
    
    // 堆排序:将待排序的序列构造成一个大顶堆(完全二叉树,根节点最大),将根节点和堆末尾元素交换,然后将剩余的元素重新构造堆,再选出最大值,反复执行
    // cout << "堆排序" << endl;
    // heap_sort(a, len);
    // print(a, len);

    // 将序列拆分成多个单个数组,再两两归并,得到有序的多个子序列,反复执行直至只有一个有序的序列为止
    // cout << "归并排序" << endl;
    // merge_sort(a, 0, len -1);
    // print(a, len);

    //快速排序:在一堆待排序记录中选择关键字,将序列分为两组,一组比关键字都小,另一组比关键字都大,递归执行,可得到一个有序序列
    cout << "快速排序" << endl;
    quick_sort(a, 0, len - 1);
    print(a, len);

    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值