一些基础算法(3)

关于排序

1.基数排序

基数排序是按各个元素的每一位上数字的大小依次排序,分为MSD和LSD两种方式,MSD是先排序最高位,然后对结果中被分到同一个组中的数据的下一位继续按位上数字大小继续排序,直到个位排完为止。LSD是先以最低位的数字大小进行排序,接着用第二位进行排序,直到最大元素的最高位排完为止。在这个过程中,可以用数组来作为排序时的桶,先找到数组中桶的分界信息并记录,再按位上数字的大小放入桶中,需要注意的是因为分界的记录是一个分组的左边界相关的,所以要从左向右遍历,以防止将相等的数据交换,造成不稳定,没有心情详细写了,直接放一个测试的程序。

#include <iostream>
#include <malloc.h>

using namespace std;


void printf_array(int array[], int begin, int end);

int get_num(int element, int digit);
int get_MaxDigit(int array[], int begin, int end);

int sort_MsdRadix_(int array[], int begin, int end, int digit);
int sort_MsdRadix(int array[], int array_num);

int sort_LsdRadix_(int array[], int begin, int end, int digit, int *bucket);
int sort_LsdRadix(int array[], int array_num);

int main(void)
{
    int     test_array[] = {2, 4, 6, 2345, 1, 2, 43, 22, 44, 54};
    int     num;

    num = sizeof(test_array) / sizeof(int);
    printf_array(test_array, 0, num - 1);
    // sort_MsdRadix(test_array, num);
    sort_LsdRadix(test_array, num);
    printf_array(test_array, 0, num - 1);

    return 0;
}


// 输出数组
void printf_array(int array[], int begin, int end)
{
    for (int i = begin; i <= end; i++)
    {
        cout << array[i] << '\t';
    }
    cout << endl;
    return;
}

/*****************************************
 * 功能:   取得一个元素某一位上的数字,即桶号
 * 参数:
 *          element:    元素
 *          digit:      元素的位,1代表第1位,即个位,2代表第二位,即十位,依次类推
 * 返回:
 *          元素element第digit位上的数字
 */
int get_num(int element, int digit)
{
    for (int i = 2; i <= digit; i++)
    {
        element = element / 10;
    }

    return element % 10;
}

/**********************************************************
 * 功能:   得到一段数组元素中元素的最大位数
 * 参数:
 *          array:      数组地址
 *          begin:      起始索引
 *          end:        末尾索引
 * 返回:
 *          MaxDigit:     最大位数
 */
int get_MaxDigit(int array[], int begin, int end)
{
    int     MaxDigit = 1;
    int     MaxVal = array[begin];

    for (int i = begin + 1; i <= end; i++)
    {
        if (array[i] > MaxVal)
        {
            MaxVal = array[i];
        }
    }
    while (MaxVal >= 10)
    {
        MaxVal /= 10;
        MaxDigit++;
    }
    
    return MaxDigit;
}

/************************************************************
 * 功能:   msd的基数排序,非降序
 * 参数:   
 *          array:      数组地址
 *          begin:      数据的第一个索引
 *          end:        最后一个索引
 *          digit:     待排序的数据中最大的位数
 * 返回:   
 *          0
 */
int sort_MsdRadix_(int array[], int begin, int end, int digit)
{
    // 首先将原始数据这个大集合分割为一些小的,某一位数字相同的数据的集合,
    // 这些集合将全部放在另一个和原始数组大小相同的数组中,另有一个有10个元素的数组用于区分各个集合的边界,
    // 按这个边界数组将原始数据重新排列到那个大小相同的数组中,最后将排列好的数据复制回原始数组中去
    int     *bucket = 0;
    int     count[10] = {0};
    int     temp1, temp2;

    if ((bucket = (int *)malloc((end - begin + 1) * sizeof(int))) == 0)
    {
        return -1;
    }

    for (int i = begin; i <= end; i++)
    {
        count[get_num(array[i], digit)]++;
    }
    for (int i = 1; i <= 9; i++)
    {
        count[i] = count[i] + count[i - 1];
    }
    
    for (int i = end; i >= begin; i--)
    {
        temp1 = get_num(array[i], digit);
        bucket[count[temp1] - 1] = array[i];
        count[temp1]--;
    }
    for(int i = begin; i <= end; i++)
    {
        array[i] = bucket[i - begin];
    }
    
    free(bucket);

    for (int i = 0; i < 9; i++)
    {
        temp1 = begin + count[i];
        temp2 = count[i + 1] - 1;

        if (temp1 < temp2 && digit > 1)
        {
            sort_MsdRadix_(array, temp1, temp2, digit - 1);
        }
    }

    return 0;
}

/*****************************************************
 * 功能:   基数排序,非降序
 * 参数:   
 *          array:      数组地址
 *          array_num:  数组长度
 * 返回:
 *          0:          成功
 *          -1:        失败
 */
int sort_MsdRadix(int array[], int array_num)
{
    int     MaxDigit;

    MaxDigit = get_MaxDigit(array, 0, array_num - 1);

    return sort_MsdRadix_(array, 0, array_num - 1, MaxDigit);
}



/**************************************************************
 * 功能:   按一位上的数字大小进行排列
 * 参数:   
 *          array:      数组地址
 *          begin:      开始索引
 *          end:        末尾索引
 *          digit:      对此位排序
 *          bucket:     辅助空间地址
 * 返回:
 *          0
 */
int sort_LsdRadix_(int array[], int begin, int end, int digit, int *bucket)
{
    // 首先将原始数据这个大集合分割为一些小的,某一位数字相同的数据的集合,
    // 这些集合将全部放在另一个和原始数组大小相同的数组中,另有一个有10个元素的数组用于区分各个集合的边界,
    // 按这个边界数组将原始数据重新排列到那个大小相同的数组中,最后将排列好的数据复制回原始数组中去
    
    int     count[10] = {0};
    int     temp;

    for (int i = begin; i <= end; i++)
    {
        count[get_num(array[i], digit)]++;
    }
    for (int i = 1; i <= 9; i++)
    {
        count[i] = count[i] + count[i - 1];
    }
    
    for (int i = end; i >= begin; i--)
    {
        temp = get_num(array[i], digit);
        bucket[count[temp] - 1] = array[i];
        count[temp]--;
    }
    for(int i = begin; i <= end; i++)
    {
        array[i] = bucket[i - begin];
    }
    
    return 0;
}

/**************************************************************
 * 功能:   lsd基数排序,非降序
 * 参数:   
 *          array:      数组地址
 *          array_num:  数组长度
 * 返回:
 *          0:          成功
 *          -1:         失败
 */
int sort_LsdRadix(int array[], int array_num)
{
    int     MaxDigit;
    int     *bucket = 0;

    if ((bucket = (int *)malloc((array_num)* sizeof(int))) == 0)
    {
        return -1;
    }

    MaxDigit = get_MaxDigit(array, 0, array_num - 1);
    for (int i = 1; i <= MaxDigit; i++)
    {
        sort_LsdRadix_(array, 0, array_num - 1, i, bucket) == 1;
    }

    free(bucket);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值