常见排序算法(三)

计数排序:

  1、一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出,它的优势在于在对一定范围内的整数排序,

     其时间复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法

  2、步骤:

    a、找出给定整数序列的最大值 max 和最小值 min,创建大小为 max-min+1 的辅助空间,其值为 0

    b、最小的那个数下标为 0,最大数下标为 -1,其他数 num 的下标为 num-min

    c、根据遍历所找到的数,在其相应下标处的值加一

    d、遍历辅助空间,输出对应下标的数,其输出次数为下标处的值,即若辅助空间 temp[0] == 5,则输出下标 0 对应的数 5 次

注:该算法是以空间换时间,若待排序列不是整数,则最好不要使用,因为浮点数范围比较大,即使像在 [0, 1) 这个区间也可以有极多个

#include <iostream>
#include <vector>
#include <algorithm>

void countSort(std::vector<int>& nums);

int main()
{
    std::vector<int> nums;
    int len = 0;
    std::cout<<"请输入长度:";
    do {
        std::cin>>len;
        if (len <= 0)
            std::cerr<<"请输入正整数:";
    } while (len <= 0);
    int num = 0;
    std::cout<<"输入 "<<len<<" 个数: ";
    for (size_t i = 0; i < len; ++i) {
        std::cin>>num;
        nums.push_back(num);
    }
    std::cout<<"排序后的数组:";
    countSort(nums);

    system("pause");

    return 0;
}

void countSort(std::vector<int>& nums)
{
//    注意要使用 ‘*‘ 号,因为它们找到的都是位置,这两个函数都包含在 algorithm 里面
    int max = *max_element(nums.begin(), nums.end());
    int min = *min_element(nums.begin(), nums.end());
    int size = max - min + 1;
//    创建辅助空间,初始化为 0
    std::vector<int> temp(size, 0);
//    将对应下标的数出现次数加一
    for (auto num : nums)
        temp[num-min] += 1;
    for (int i = 0; i < size; ++i) {
        int count = temp[i];
//        根据次数输出,我们在这里没有改变原序列的顺序,
//        仅仅输出排序后的序列,若要改变原序列,需要执行复制操作
        while (count > 0) {
            std::cout<<i+min<<std::ends;
            count--;
        }
    }
    std::cout<<std::endl;
}

基数排序:

  1、基数排序是根据待排序列的元素的位来进行排序的,是一种非比较排序;它可以分为两类:

      最低位优先法,简称 LSD 法:先从最低位开始排序,再对次低位排序,直到对最高位排序后得到一个有序序列

      最高位优先法,简称 MSD 法:先从最高位开始排序,再逐个对各分组按次高位进行子排序,循环直到最低位

      以下是 LSD 的动态演示图

  2、步骤(LSD):

    a、根据待排序的元素的最多位数确定循环次数,如最多位的数位 12345,则循环 5 次

    b、创建 10 张空表,分别表示 0~9

    c、从最低位开始,根据位上的数值选择放入的表,如 123 在最低位上的数为 3,则放到下标为 3 的表里

    d、按顺序将表里的元素取出,替换原序列的数

    e、向高移动一位,重复操作 c 和 d,直至循环次数

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cstdlib> 

int get_times(int num);
int get_digit(int num, int d);
void radixSort(std::vector<int>& nums);

int main()
{
    std::vector<int> nums;
    int len = 0;
    std::cout<<"请输入长度:";
    do {
        std::cin>>len;
        if (len <= 0)
            std::cerr<<"请输入正整数:";
    } while (len <= 0);
    int num = 0;
    std::cout<<"输入 "<<len<<" 个数: ";
    for (size_t i = 0; i < len; ++i) {
        std::cin>>num;
        nums.push_back(num);
    }
    radixSort(nums);
    std::cout<<"排序后的数组:";
    for (int num : nums)
        std::cout<<num<<std::ends;
    std::cout<<std::endl;

    system("pause");

    return 0;
}

// 获取第 d 位的数值
int get_digit(int num, int d)
{
    return int(num / pow(10, d)) % 10;
}

// 获取需要循环的次数
int get_times(int num)
{
    int times = 0;
    while (num) {
        times++;
        num /= 10;
    }
    return times;
}

//没有考虑负数的情况,如果需要的话可以使用两个数组,一个存放正数,一个存放负数
void radixSort(std::vector<int>& nums)
{
    int max = *max_element(nums.begin(), nums.end());
    int times = get_times(max);
    int len = nums.size();

    for (size_t i = 0; i < times; ++i) {
        std::vector<std::vector<int>> temp(10);
        for (int num : nums) {
            temp[get_digit(num, i)].push_back(num);
        }
                // 清除数组内容
        nums.clear();
                // 赋值
        for (auto vec : temp) {
            for (int num : vec) {
                nums.push_back(num);
            }
        }
    }
    return ;
}

桶排序:

  1、扫描选出待排序列的最大 max 和最小值 min,设有 k 个桶,则我们把区间 [min, max] 均匀地划分为 k 个区间,

     每个区间就是一个桶,然后再将待排序列地元素分配到各自的桶里,即数值的大小在哪个区间就分配到哪

  2、对每个桶里的元素进行排序,可以选择任意一种算法

  3、将各个桶里的元素合并成一个大的有序序列

#include <iostream>
#include <vector>
#include <cstdlib>
#include <algorithm>

void bucketSort(std::vector<int>& num);

int main()
{
    std::vector<int> nums;
    int len = 0;
    std::cout<<"请输入长度:";
    do {
        std::cin>>len;
        if (len <= 0)
            std::cerr<<"请输入正整数:";
    } while (len <= 0);
    int num = 0;
    std::cout<<"输入 "<<len<<" 个数: ";
    for (size_t i = 0; i < len; ++i) {
        std::cin>>num;
        nums.push_back(num);
    }

    std::cout<<"排序后的数组:";
    bucketSort(nums);

    system("pause");

    return 0;
}

//这个排序我没有改变原序列的顺序,仅仅只是输出有序序列,若要改变原序列,请添加赋值操作
void bucketSort(std::vector<int>& nums)
{
//    寻找最大最小值
    int max = *max_element(nums.begin(), nums.end());
    int min = *min_element(nums.begin(), nums.end());

//    为方便起见,桶个数直接采用范围大小
    int buckets_num = max-min+1;
    std::vector<std::vector<int>> res(buckets_num);

    for (int num : nums) {
//        按数压入
        res[num-min].push_back(num);
    }

    for (auto vec : res) {
//        桶内排序
        sort(vec.begin(), vec.end());
    }

    for (auto vec : res)
        for (int num : vec)
            std::cout<<num<<std::ends;
    std::cout<<std::endl;

    return ;
}

原文地址:https://www.cnblogs.com/lemonyam/p/10832680.html

时间: 2024-11-08 07:46:33

常见排序算法(三)的相关文章

【整理】常见排序算法及其时间复杂度总结

原文出处: 1. 白话经典算法系列之八 MoreWindows白话经典算法之七大排序总结篇 2. 面试常用算法总结--排序算法(java版) 3. 常见排序算法小结 本篇主要整理了冒泡排序,直接插入排序,直接选择排序,希尔排序,归并排序,快速排序,堆排序七种常见算法,是从上面三篇博文中摘抄整理的,非原创. 一.冒泡排序 主要思路是: 通过交换相邻的两个数变成小数在前大数在后,这样每次遍历后,最大的数就"沉"到最后面了.重复N次即可以使数组有序. 冒泡排序改进1: 在某次遍历中,如果没有

几种常见排序算法

几种常见排序算法 几种常见排序算法 写在前面 基础介绍 初级排序算法 selection sort选择排序 insertion sort插入排序 ShellSort希尔排序 shuffing不是排序算法 merge sort归并排序 Abstract in-place merge原地归并的抽象方法 Top-down mergesort自顶向下的归并排序 Bottom-up mergesort自底向上的归并排序 quicksort 三向切分的快速排序 Heapsort堆排序 总结和比较 命题 本文

第六章 常见排序算法

上章回顾 二叉树的定义 树深度的定义 什么样的二叉树是满二叉树 中序遍历的规则 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git 第六章 第六章 常见排序算法 常见排序算法 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorith

常见排序算法总结(java实现)

所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.常见的排序算法有选择排序,插入排序,希尔排序,归并排序和快速排序 由于在排序的过程中不可避免的要涉及到比较和交换,所以将他们抽取为两个单独的函数,如下所示 //为了排序代码的通用性,这里假定待排序的元素实现了Comparable接口 private static boolean less(Comparable v ,Comparable w){ return v.compareTo(w)<0; } priva

常见排序算法(一) MergeSort

算法思想灰常重要,常见的用到分治思想的算法包括快速排序,归并,二分搜搜,大整数乘法等(参考 http://blog.csdn.net/com_stu_zhang/article/details/7233761,归纳很到位) 简单用归并对一个数组排序 思路: 简单来说对一个数组,只要他的左右两部分都是有序的,那么简单合并就ok了,那么左右两部分可以进一步划分各自的左右两部分----明显就是要递归了 算法:归并排序 1. 将数组一分为二,subArray1 和subArray2 2. 归并排序sub

常见排序算法(java实现)

常见排序算法介绍 冒泡排序 代码: public class BubbleSort { public static void sort(int[] array) { int tValue; for (int i = 0; i < array.length; i++) { for (int j = i; j < array.length; j++) { if (array[i] > array[j]) { tValue = array[i]; array[i] = array[j]; ar

常见排序算法(冒泡、选择、插入、快速、归并C++实现)

常见排序算法(冒泡.选择.插入.快速.归并C++实现) #include <iostream> using namespace std; // 冒泡排序 void bubbleSort (int data[], size_t size) { for (size_t i = 0; i < size - 1; ++i) { bool ordered = true; for (size_t j = 0; j < size - 1 - i; ++j) if (data[j+1] <

十种常见排序算法

1.常见算法分类 十种常见排序算法一般分为以下几种: (1)非线性时间比较类排序:交换类排序(快速排序和冒泡排序).插入类排序(简单插入排序和希尔排序).选择类排序(简单选择排序和堆排序).归并排序(二路归并排序和多路归并排序): (2)线性时间非比较类排序:计数排序.基数排序和桶排序. 总结: (1)在比较类排序中,归并排序号称最快,其次是快速排序和堆排序,两者不相伯仲,但是有一点需要注意,数据初始排序状态对堆排序不会产生太大的影响,而快速排序却恰恰相反. (2)线性时间非比较类排序一般要优于

常见排序算法(PHP实现)

function InsertSort($arr){ $num = count($arr); for($i = 1; $i < $num; $i++){ $key = $arr[$i]; for($j = $i - 1; $j >= 0; $j--){ if($arr[$j] > $key){ $arr[$j + 1] = $arr[$j]; $arr[$j] = $key; } } } return $arr; } function BubbleSort($arr){ $num = c

常见排序算法(JS版)

常见排序算法(JS版)包括: 内置排序,冒泡排序,选择排序,插入排序,希尔排序,快速排序(递归 & 堆栈),归并排序,堆排序,以及分析每种排序算法的执行时间. index.html 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>twobin 常见排序算法 (JS版) </title> 5 <meta http-equiv="content-type" content=&