线性时间排序

1.计数排序

基本思想:对于每一个输入元素x,确定小于(或等于)x的元素个数,就可以确定x的存放位置.

特点:稳定排序

#include<iostream>
#include<vector>
using namespace std;

void count_sort(vector<int> A,vector<int> &B,int k){
    vector<int> C(k+1,0);
    for(int j=0;j<A.size();j++){
        C[A[j]] = C[A[j]]+1;//或C[A[j]]++;C[i]包含了等于i的元素的个数
    }
    for(int i=1;i<=k;i++){
        C[i] = C[i] +C[i-1];//C[i]包含了不大于i的元素的个数
    }
    for(int j=A.size()-1;j>=0;j--){
        B[C[A[j]]-1] = A[j];//C[A[j]]描述的是位置,下标应该再-1
        C[A[j]] = C[A[j]] -1;
    }
}

int main(){
    vector<int> A{9,2,4,3,5,6,8,7,1,9,6};
    vector<int> B(A.size(),0);
    count_sort(A,B,9);
    for(const auto &c:B){
        cout<<c<<",";
    }
    cout<<endl;
    return 0;
}

2.基数排序

基本思路:采用稳定排序算法从低位到高位对数据的每一位进行排序.

#include<iostream>
#include<vector>
using namespace std;

void count_sort(vector<int> &a,int i,int k){//i表示数据的第i位,k表示每位的最大值
    vector<int> b(a.size(),0);//保存排序后的a
    vector<int> c(k+1,0);
    vector<int> d(a.size(),0);//保存每个元素的第i位
    for(int j=0;j<a.size();j++){
        int r=a[j];
        int x=i;//不能改变i的值
        while(x>0){
            d[j] = r%10;
            r = r/10;
            --x;
        }
    }
    for(int j=0;j<a.size();j++){
        c[d[j]]++;//利用d而不是a来计算c
    }
    for(int i=1;i<=k;i++){
        c[i] = c[i]+c[i-1];
    }
    for(int j=a.size()-1;j>=0;j--){
        b[c[d[j]]-1] = a[j];//保存a[j]而不是d[j]
        c[d[j]] =c[d[j]] -1;
    }
    a=b;
}

void radix_sort(vector<int> &a,int d){
    for(int i=1;i<=d;i++){
        count_sort(a,i,9);
    }
}

int main(){
    vector<int> a{329,457,657,839,436,720,355,97};
    radix_sort(a,3);
    for(const auto &c:a){
        cout<<c<<",";
    }
    cout<<endl;
    return 0;
}

3.桶排序

计数排序假设数据都属于一个小区间内的整数,而桶排序假设输入是由一个随机过程产生,该过程将元素均匀独立地分布在[0,1)区间上.桶排序将[0,1)区间划分为n个大小相同的子区间,即桶.然后将n个输入分别放入各个桶中.先对每个桶中的元素排序,然后依次遍历每个桶,即可得到有序序列.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

void bucket_sort(vector<double> a){
    int n = a.size();
    vector<double> b[n];
    for(int i=0;i<n;i++){
        b[static_cast<int>(n*a[i])].push_back(a[i]);//将元素放入桶中
    }
    for(int i=0;i<n;i++){
        sort(b[i].begin(),b[i].end());//对每个桶中的元素排序
    }
    for(const auto &x:b){
        for(const auto &y:x){
            cout<<y<<",";
        }
    }
    cout<<endl;
}

int main(int argc, char const *argv[])
{
    vector<double> a{0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.68};
    bucket_sort(a);
    return 0;
}

线性排序算法使用最重要的是,充分利用数据特殊的性质,以达到最佳效果。(source)

时间: 2024-08-26 00:05:10

线性时间排序的相关文章

排序算法(4)-线性时间排序

在前面三节排序算法中,我们分别分析了不同策略,思想用于排序,而这些算法都是基于数据间的比较来确定顺序的.假设我不用比较,换一种思路,那么就可以达到时间复杂度为O(n)的排序算法,当然是以付出额外的空间为代价的. 一.基本思想 线性时间排序的算法思想: (1):在计数排序中,利用比x小或等的元素个数和的来确定x位置.比如2 5 4 9 1 6.9比其余5个数都大,那就说明9 在排序后的第6个位置,这样我们只要得到比某个数大的元素个数就能得到元素在排序后数组中的位置了. (2):在桶排序中,是通过映

第八章 线性时间排序 8.3 基数排序

package chap08_Linear_Time_Sort; import static org.junit.Assert.*; import java.util.Arrays; import org.junit.Test; public class CopyOfSortAlgorithms { /** * 基数排序 * * @param n * @param digit */ static void radixSort(int[] n, int digit) { int[] b = new

算法导论 第八章 线性时间排序(python)

比较排序:各元素的次序依赖于它们之间的比较{插入排序O(n**2) 归并排序O(nlgn) 堆排序O(nlgn)快速排序O(n**2)平均O(nlgn)} 本章主要介绍几个线性时间排序:(运算排序非比较排序)计数排序O(k+n)基数排序O() 第一节:用决策树分析比较排序的下界 决策树:倒数第二层满,第一层可能满的二叉树,它用来表示所有元素的比较操作{于此来分析下界},忽略控制,移动操作 1:2 #A[1]和A[2]比 <= 走左边 >走右边 <3,1,2> 最后的结果 下标对应排

算法导论 第8章 线性时间排序

合并排序和堆排序的时间复杂度为O(nlgn),插入排序和冒泡排序的时间复杂度为O(n^2),快速排序的时间复杂度在平均情况下是O(nlgn),这些排序算法都是通过对元素进行相互比较从而确定顺序的,因此都叫比较排序. 比较排序可以看做是决策树(一个满二叉树),因为每一次比较都是一个分支.n个元素的序列,其排序的结果有 n! 种可能(n个元素的全排),所以这个决策树有 n! 个叶子结点,假设树的高度为h,则有:n! <= 2^h,所以h >= lg(n!) = Ω(nlgn).一次比较排序就是从决

算法导论-- 线性时间排序(计数排序、基数排序、桶排序)

线性时间排序 前面介绍的几种排序,都是能够在复杂度nlg(n)时间内排序n个数的算法,这些算法都是通过比较来决定它们的顺序,这类算法叫做比较排序 .下面介绍的几种算法用运算去排序,且它们的复杂度是线性时间. -------------------------------------- 1.计数排序 计数排序采用的方法是:对每个元素x,去确定小于x的元素的个数,从而就可以知道元素x在输出数组中的哪个位置了. 计数排序的一个重要性质是它是稳定的,即对于相同的两个数,排序后,还会保持它们在输入数组中的

线性时间排序算法

线性时间排序算法列表 线性时间排序 Name Average Worst Memory Stable Description  计数排序 (Counting Sort) n + k n + k n + k Stable Indexes using key values.  基数排序 (Radix Sort) n * k  n * k n + k Stable Examines individual bits of keys.  桶排序 (Bucket Sort) n + k n2 n * k S

算法导论第八章线性时间排序

一.线性时间排序算法历史概览 计数排序首先是由 Harold H. Seward 于1954年提出,而且他还提出将计数排序和基数排序进行结合的思想:基数排序是L.J.Comrie于1929年首次在一篇描述卡片穿孔机文档中提出的一种方法,它是从最低有效位开始,对一个有多位数组成的数进行排序的方法:而桶排序的基本思想则由E.J.Isaac和R.C.Singleton于1956年提出的,之后很多研究人员在这三种算法的基础上针对不同的应用场景又进一步改进,到了今天一个很成熟.很通用的地步. 二.O(nl

算法导论之六:线性时间排序之 决策树&amp;计数排序

本系列前五篇都是讲述的比较排序算法,从本文开始,将进入线性时间排序.什么是比较排序,简单的说,就是排序的过程依赖于数组中数据大小的比较,从而来确定数据在排好序输出时的位置. 比较排序法比较直观,但是也有它的不足,我们容易证明任何比较排序法,在最坏的情况下的时间复杂度的下限都是 nlgn.要证明这个问题,我们首先要搞清楚一个模型:决策树模型. 一.决策树模型 什么是决策树?决策树从形态上来讲,是一颗完全二叉树,它除叶子节点之外,其他层的节点都是满的.它的每一个叶子节点表示对输入数据组合的一种排序可

算法导论——lec 08 线性时间排序

之前我们介绍了几种O(nlgn)的排序算法:快速排序.合并排序和堆排序,本节我们介绍基于比较的排序算法的下界以及几个线性时间的排序算法--计数排序.基数排序.桶排序. 一. 比较排序算法的下界 1. 决策树模型:比较排序可以被抽象的视为决策树.一棵决策树是一棵满二叉树,表示某排序算法 作用于给定输入所做的所有比较. 排序算法的执行对应于遍历一条从树的根到叶结点的路径.在每个内节结点处要做比较. 要使排序算法能正确的工作,其必要条件是,n 个元素的n!种排列中的每一种都要作为决策树 的一个叶子而出

读书日记- 线性时间排序算法

在最坏情况下,任何比较排序算法都需要做O(nlgn)次比较. 然而,在指定的条件下,线性时间的排序算法可以使得排序在O(n)时间内完成. 计数排序 假设n个输入元素中的每一个都是0到k区间内的一个整数,其中k为某个整数.k=O(n)时,排序运行时间为O(n). 主要思想: 创建长度为k的数组C,将对应的输入数组A的值作为索引来统计k数组每个下标出现的次数. 代码如下: void Counting_Sort(int* intArr,int* outArr,int k,int len) { int*