前面介绍了一些常用的比较排序算法,它们都是通过比较两个元素的大小进行排序,归并排序和堆排序在最坏情况下的复杂度为O(nlgn),可以证明(使用决策树模型),通过比较进行排序,算法的下界为O(nlgn),因此,归并排序和堆排序是渐进最优的算法,快速排序在平均情况也可达到该下界。

不过,对于一些特殊的输入元素,可以在线性时间完成排序,常见的算法有计数排序、基数排序、桶排序。

计数排序

计数排序假设n个输入元素每一个都是在0到k之间的整数,k为某个整数,当k=O(n)时,计数排序的运行时间为O(n)。

思想:对于每一个输入元素x,计算小于x的元素个数,通过这一信息,可以确定x在排序后的位置,将其正确放置即可。如小于x的元素有4个,那么x应该放在第5个位置上,以此类推。当然,若有多个元素相同,又不可能将它们放置在同一位置,则要在遍历过程中动态修改小于等于x的个数,如:有a个元素小于等于x,且x的值重复出现b次,则遇到第一个x时,将其放在第a位,并使a减1,下次遇到x,则放在第a-1位,最终,b个x放置的位置为(a-b ... a)。算法的核心步骤是如何在线性时间确定小于x的元素个数,这就是假设元素在0到k之间的原因。

#include<iostream>
#define k 100 //输入元素大小在0-99之间。
using namespace std;
void counting_sort(int* A, int* B, int len){
int c[k] = {};
for(int i=;i<len;i++)
c[A[i]] += ;
for(int i=;i<k;i++)
c[i] += c[i-];
for(int i=len-;i>=;i--){ //从后往前遍历数组,可以保证排序的稳定性,具有相同值的元素在排序后相对次序不变。
B[c[A[i]]-] = A[i];
c[A[i]] -= ;
}
} int main(){
int A[] = {,,,,,,,,};
int B[];//排序后的数组
counting_sort(A, B, );
for(int i=;i<;i++)
cout<<B[i]<<" ";
cout<<endl;
}

基数排序

基数排序是一种用在卡片排序机上的算法,其基本过程是对于n个d位整数,从低位到高位依次进行排序,d位数则需要进行d次排序操作,排序使用稳定的排序算法,如计数排序。

为何需要稳定的排序算法呢?下面举个简单的例子说明一下:

假设输入元素为4个3位数,

375

491

604

465

第一次,对最低位进行排序(最右列),结果为

491

604

375

465

第二次,对中间列进行排序:

604

375

465

491

第三次,对最高位进行排序:

375

465

491

604

以上是稳定排序的结果,若排序算法不稳定,那么在第三次排序后得到的结果可能是

375

491

465

604

这是错误的,虽然保证了最高位按照顺序排列,但最高位相同时,中间列的大小关系就起到关键作用,不稳定的排序算法会导致中间列的相对顺序改变,从而得到错误的结果。

桶排序

桶排序假设输入数据服从均匀分布,则平均情况下,时间代价为O(n)。

思想:桶排序与计数排序类似,都对输入数据进行假设,桶排序假设输入数据由一个随机过程均匀独立的分布在[0,1)区间上,将[0,1)区间划分为n个大小相同的子区间(桶),然后将n个输入数据分别放在各个桶中,先对每个桶中元素排   序,然后按照桶的次序输出桶中的元素。

#include<iostream>
#define len 10
using namespace std;
struct node{
double key;
struct node* next;
}; //定义链表结点 void Insert_Sort(node*& head){ //对链表使用插入排序
node* t = head;
while(t->next){
node* p = head;
node* pre = NULL;
node* q = t->next;
while(p != q){
if(p->key >= q->key)
break;
pre = p;
p = p->next;
}
if(pre == NULL){
head = q;
t->next = q->next;
q->next = p;
}
else if(p != q){
pre->next = q;
t->next = q->next;
q->next = p;
}
else
t = t->next;
}
} void Bucket_Sort(double A[]){
node* B[len]; //使用指针数组B作为桶存放数据。
for(int i=;i<len;i++)
B[i] = NULL;
for(int i=;i<len;i++){ //将输入元素A[]放入桶中(B[])。
node* p = new node;
p->key = A[i];
p->next = B[int(len*A[i])];
B[int(len*A[i])] = p;
}
int j = ;
for(int i=;i<len;i++) //将桶中数据排序后依次插入数组A中
if(B[i] != NULL){
Insert_Sort(B[i]);
node* t = B[i];
while(t){
A[j++] = t->key;
node* d = t;
t = t->next;
delete d;
}
}
} int main(int argc, char* argv[]){
double A[len] = {0.93, 0.41, 0.44, 0.26, 0.82, 0.31, 0.67, 0.94, 0.37, 0.62};
Bucket_Sort(A);
for(int i=;i<len;i++)
cout<<A[i]<<" ";
cout<<endl;
return ;
}

线性排序总结(c++实现)的更多相关文章

  1. Maximum Gap 典型线性排序

    https://leetcode.com/problems/maximum-gap/ Given an unsorted array, find the maximum difference betw ...

  2. o(n)线性排序算法

    O(n) 排序算法 前言 前面有总结过各类常用的排序算法,但是那些排序算法最优的时间复杂度是O(nlogn),所以我要介绍三种时间复杂度为O(n)的线性时间复杂度的排序算法. 计数排序 计数排序利用了 ...

  3. python实现线性排序-基数排序

    基数排序算法是一种是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较. 由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于 ...

  4. python实现线性排序算法-计数排序

    计数排序假定输入元素的每一个都是介于0到k之间的整数,此处K为某个整数,当k=O(n)时,计数排序的运行时间为O(n) 它的基本思想是:根据每个输入元素x确定小于x的元素个数,根据这个信息把x直接放到 ...

  5. 算法分析-插入排序INSERT_SORT与选择排序SELECT_SORT【线性方法】

    var A = [5, 2, 4, 6, 1, 3]; console.log("排序前-:") A.forEach(function (element, index, arr) ...

  6. 排序算法的C语言实现(下 线性时间排序:计数排序与基数排序)

    计数排序 计数排序是一种高效的线性排序. 它通过计算一个集合中元素出现的次数来确定集合如何排序.不同于插入排序.快速排序等基于元素比较的排序,计数排序是不需要进行元素比较的,而且它的运行效率要比效率为 ...

  7. 七种机器内部排序的原理与C语言实现,并计算它们的比较次数与移动次数。

    内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列. 排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列.排序分为 ...

  8. 冒泡排序 & 选择排序 & 插入排序 & 希尔排序 JavaScript 实现

    之前用 JavaScript 写过 快速排序 和 归并排序,本文聊聊四个基础排序算法.(本文默认排序结果都是从小到大) 冒泡排序 冒泡排序每次循环结束会将最大的元素 "冒泡" 到最 ...

  9. 基本排序算法的Python实现

    本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序,希尔排序,归并排序,快速排序,堆排序,计数排序.希望大家回顾知识的时候也能从我的这篇文章得到帮助. 为了防止误导读者,本文所有概念性 ...

随机推荐

  1. 冰多多团队Gamma阶段发布说明

    Bingduoduo 语音Coding(Gamma):项目Github地址 Gamma版本新功能介绍 在gamma阶段我们推出了一个更加完整的IDE,完善了部分编辑器功能,并且优化了UI,增添了新的s ...

  2. Yarn和Zookeeper的区别

    Yarn:分布式资源管理器 Zookeeper:分布式协作服务 Zookeeper是一个分布式协调服务(Coordination),一个leader,多个follower组成的集群,就是为用户的分布式 ...

  3. .netcore使用MimeKit发送邮件

    以163邮箱为例,借助MimeKit nuget安装:MimeKit类库,源码地址:https://github.com/jstedfast/MimeKit 发送方法如下: #region 邮件发送 ...

  4. windows下elasticsearch安装ik分词器后无法启动

    windows下elasticsearch安装ik分词器后启动报如下图错误: 然后百度说是elasticsearch路径有空格,一看果然我的路径有空格,然后重新换个路径就好了.

  5. CSP2019-S游记

    目录 CSP2019-S游记 Day -2(UPDATE:2019-11-14) Day -1(UPDATE:2019-11-15) Day 1(UPDATE:2019-11-16) Day 2(UP ...

  6. 能写数据后台,需要掌握哪些进阶的sql语句?

    国庆假期花了一些时间,首次尝试并玩转 grafana,这几天继续不断优化和完善,如今看着自己的成果,相当满意.--逐步接近我想要的理想后台啦. 需求是不停歇的.今天我又给自己发掘了一些新需求,比如变量 ...

  7. SetWindowLong函数GetWindowLong函数

    这两个函数具体应用如下:SetWindowLong函数GetWindowLong函数 Delphi窗口化游戏 var Thwnd:HWND;//声明变量 句柄变量 devmodel1:DEVMODE; ...

  8. 关于VS2019使用Git时遇到的Bug

    最近在运行vs2017时老是卡死,神烦!迫于无奈我从微软官网下载了vs2019,安装后打开项目,发现从git上拉取代码时报错如下: Please make sure you have the corr ...

  9. mvc_第一章后入门_第一遍_控制器和视图

    在掌握了数据库访问方法之后,我们来看几个mvc的入门程序,借此熟悉mvc的常见工作方式. 一.创建项目,显示一个最简单的页面. 要点:1.为了突出重点,不使用模版:2.项目类型为mvc,便于获得vs添 ...

  10. ios app UI自动化测试用到的命令

    ios测试的app测试包,真机设备需要开发者证书并且将测试机的udid加入到pp文件文件,configruation 要求为debug模式的ipa包, 1.苹果手机的UDID, a.通过 xcode- ...