[算法] O(n^2)排序算法的效率比较
选择、插入排序
main.cpp
1 #include <iostream>
3 #include "SortTestHelper.h"
4
5 using namespace std;
6
7 template<typename T>
8 void selectionSort(T arr[],int n){
9 for(int i = 0 ; i < n ; i ++){
10 int minIndex = i;
11 for( int j = i + 1 ; j < n ; j ++ )
12 if( arr[j] < arr[minIndex] )
13 minIndex = j;
14 swap( arr[i] , arr[minIndex] );
15 }
16 }
17
18 template<typename T>
19 void insertionSort(T arr[],int n){
20 for(int i = 1 ; i < n ; i++ ){
21 T e = arr[i];
22 int j;
23 for(j = i ; j > 0 && arr[j-1] > e ; j --)
24 arr[j] = arr[j-1];
25 arr[j] = e;
26 }
27 }
28
29 int main(){
30 int n = 100000;
31 int *arr = SortTestHelper::generateNearlyOrderedArray(n,10);
32
33 SortTestHelper::testSort("Insertion Sort",insertionSort,arr,n);
34 SortTestHelper::testSort("Selection Sort",selectionSort,arr,n);
35
36 delete[] arr;
37 return 0;
38 }
SortTestHelper.h
1 #include <iostream>
2 #include <ctime>
3 #include <cassert>
4 #include <string>
5
6 using namespace std;
7
8 namespace SortTestHelper{
9 int *generateRandomArray(int n,int rangeL,int rangeR){
10 assert(rangeL <= rangeR);
11 int *arr = new int[n];
12 srand(time(NULL));
13 for(int i = 0 ; i < n ; i++)
14 arr[i] = rand()%(rangeR-rangeL+1) + rangeL;
15 return arr;
16 }
17
18 int *generateNearlyOrderedArray(int n, int swapTimes){
19 int *arr = new int[n];
20 for(int i = 0 ; i < n ; i ++ )
21 arr[i] = i;
22 srand(time(NULL));
23 for( int i = 0 ; i < swapTimes ; i ++){
24 int posx = rand()%n;
25 int posy = rand()%n;
26 swap( arr[posx] , arr[posy] );
27 }
28 return arr;
29 }
30
31 template<typename T>
32 void printArray(T arr[],int n){
33 for(int i = 0;i<n;i++)
34 cout << arr[i] <<" ";
35 cout << endl;
36 return;
37 }
38
39 template<typename T>
40 bool isSorted(T arr[],int n){
41 for(int i = 0 ; i<n-1 ; i++)
42 if(arr[i] > arr[i+1])
43 return false;
44 return true;
45 }
46 template<typename T>
47 void testSort(const string &sortName,void (*sort)(T[],int),T arr[],int n){
48
49 clock_t startTime = clock();
50 sort(arr,n);
51 clock_t endTime = clock();
52
53 assert(isSorted(arr,n));
54
55 cout << sortName << " : " << double(endTime-startTime)/CLOCKS_PER_SEC << " s" <<endl;
56
57 return;
58 }
59 }
结果
插入排序快的原因
- 可提前终止循环
- 没有交换操作
- 对近乎有序数组,插入排序会更快,甚至快于O(nlogn)级算法,在实际中有大量应用
冒泡排序
方法1
1 template<typename T>
2 void bubbleSort( T arr[] , int n){
3
4 bool swapped;
5
6 do{
7 swapped = false;
8 for( int i = 1 ; i < n ; i ++ )
9 if( arr[i-1] > arr[i] ){
10 swap( arr[i-1] , arr[i] );
11 swapped = true;
12
13 }
14
15 // 优化, 每一趟Bubble Sort都将最大的元素放在了最后的位置
16 // 所以下一次排序, 最后的元素可以不再考虑
17 n --;
18
19 }while(swapped);
20 }
方法2
1 template<typename T>
2 void bubbleSort2( T arr[] , int n){
3
4 int newn; // 使用newn进行优化
5
6 do{
7 newn = 0;
8 for( int i = 1 ; i < n ; i ++ )
9 if( arr[i-1] > arr[i] ){
10 swap( arr[i-1] , arr[i] );
11
12 // 记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑
13 newn = i;
14 }
15 n = newn;
16 }while(newn > 0);
17 }
优化
- 每轮循环如果没有发生交换,就代表数据已经有序,提前退出
- 每轮循环中后面的元素如果已经有序,下一轮循环就不再考虑
三种O(n^2)级别算法的思路:
- 冒泡排序:相邻元素作比较,每次循环后最大的元素放在最后
- 选择排序:找到后面最小的元素,每次循环后最小的元素放在最前
- 插入排序:将新元素插入到有序数组中合适的位置
时间复杂度比较
- 选择排序:比较+交换。对于最好和最坏情况,比较的次数是一样多的,均为n(n-1)/2,最好情况交换0次,最坏情况交换n-1次,故总的时间复杂度为O(n2)
- 插入排序:比较+赋值。最好情况为顺序,只需比较前面的一个元素即可,不需要赋值,复杂度O(n),最坏情况为逆序,需要和前面所有的数都进行比较和赋值,复杂度O(n2)
- 单向链表插入排序:比较+插入,链表插入的复杂度是O(1),故主要时间消耗在比较上,即为新元素找到合适的位置插入,对于逆序,每次新元素只要完成插入即可,时间消耗O(n);对于顺序,每个新元素都要从头遍历(单向链表,无法直接比较前一个元素),与每个元素进行比较,时间消耗O(n2)
[算法] O(n^2)排序算法的效率比较的更多相关文章
- 数据结构和算法(Golang实现)(25)排序算法-快速排序
快速排序 快速排序是一种分治策略的排序算法,是由英国计算机科学家Tony Hoare发明的, 该算法被发布在1961年的Communications of the ACM 国际计算机学会月刊. 注:A ...
- 数据结构和算法(Golang实现)(19)排序算法-冒泡排序
冒泡排序 冒泡排序是大多数人学的第一种排序算法,在面试中,也是问的最多的一种,有时候还要求手写排序代码,因为比较简单. 冒泡排序属于交换类的排序算法. 一.算法介绍 现在有一堆乱序的数,比如:5 9 ...
- 数据结构和算法(Golang实现)(20)排序算法-选择排序
选择排序 选择排序,一般我们指的是简单选择排序,也可以叫直接选择排序,它不像冒泡排序一样相邻地交换元素,而是通过选择最小的元素,每轮迭代只需交换一次.虽然交换次数比冒泡少很多,但效率和冒泡排序一样的糟 ...
- 数据结构和算法(Golang实现)(21)排序算法-插入排序
插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑 ...
- 数据结构和算法(Golang实现)(22)排序算法-希尔排序
希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机 ...
- 数据结构和算法(Golang实现)(23)排序算法-归并排序
归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_ ...
- 数据结构和算法(Golang实现)(24)排序算法-优先队列及堆排序
优先队列及堆排序 堆排序(Heap Sort)由威尔士-加拿大计算机科学家J. W. J. Williams在1964年发明,它利用了二叉堆(A binary heap)的性质实现了排序,并证明了二叉 ...
- 链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述
关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学 ...
- 冒泡排序算法和简单选择排序算法的js实现
之前已经介绍过冒泡排序算法和简单选择排序算法和原理,现在有Js实现. 冒泡排序算法 let dat=[5, 8, 10, 3, 2, 18, 17, 9]; function bubbleSort(d ...
- 数据结构和算法(Golang实现)(18)排序算法-前言
排序算法 人类的发展中,我们学会了计数,比如知道小明今天打猎的兔子的数量是多少.另外一方面,我们也需要判断,今天哪个人打猎打得多,我们需要比较. 所以,排序这个很自然的需求就出来了.比如小明打了5只兔 ...
随机推荐
- [树形DP]电子眼
电 子 眼 电子眼 电子眼 题目描述 中山市石一个环境优美.气候宜人的小城市.因为城市的交通并不繁忙,市内的道路网很稀疏.准确地说,中山市有N-1条马路和N个路口,每条马路连接两个路口,每两个路口之间 ...
- Java利用线程工厂监控线程池
目录 ThreadFactory 监控线程池 扩展线程池 扩展线程池示例 优化线程池大小 线程池死锁 线程池异常信息捕获 ThreadFactory 线程池中的线程从哪里来呢?就是ThreadFoct ...
- 基于scrapy框架的爬虫基本步骤
本文以爬取网站 代码的边城 为例 1.安装scrapy框架 详细教程可以查看本站文章 点击跳转 2.新建scrapy项目 生成一个爬虫文件.在指定的目录打开cmd.exe文件,输入代码 scrapy ...
- Element源码:项目初始化和webpack配置
0x00.项目初始化 由于整个过程像素级 copy element,所以将不使用vue-cli初始化项目. 创建项目 新建一个空的文件夹,使用npm init 来初始化项目,并安装vue模块. 修改目 ...
- 翻译:《实用的Python编程》09_02_Third_party
目录 | 上一节 (9.1 包) | 下一节 (9.3 版本分发) 9.2 第三方模块 Python 拥有一个包含各种内置模块的大型库(自带电池(batteries included))(译注:&qu ...
- @Scheduled注解
1 概述 @Scheduled注解是spring boot提供的用于定时任务控制的注解,主要用于控制任务在某个指定时间执行,或者每隔一段时间执行.注意需要配合@EnableScheduling使用,配 ...
- 敏捷史话(十五):我发明了敏捷估算扑克牌 —— James Greening
雪鸟会议 雪鸟会议前夕,James Grenning 在 Object Mentor 与 Robert C. Martin 一同工作,彼时组织雪鸟会议的 Bob 大叔盛情邀请 James,告知他会议的 ...
- Ubuntu 快速安装Gitlab-ce
1.下载并安装gitlab,下载地址: https://packages.gitlab.com/gitlab/gitlab-ce/ sudo dpkg -i gitlab-ce_12.0.3-ce.0 ...
- CAP 5.0 版本发布通告
前言 今天,我们很高兴宣布 CAP 发布 5.0 版本正式版.同时我们也很高兴的告诉你 CAP 已经有越来越多的用户并且变得越来越流行. 在 5.0 版本中,我们主要致力于更好的支持 .NET 5 以 ...
- math random模块
math --- 数学函数 该模块提供了对C标准定义的数学函数的访问,返回值除非有明确说明,否则所有返回值均为浮点数 math.ceil(x) 返回 x 的上限,即大于或者等于 x 的最小整数. 如果 ...