插入排序,又叫直接插入排序。实际中,我们玩扑克牌的时候,就用了插入排序的思想。
基本思想:在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。
希尔排序,又称缩小增量法。其基本思想是:
1>先选定一个小于N的整数gap作为第一增量,然后将所有距离为gap的元素分在同一组,并对每一组的元素进行直接插入排序。然后再取一个比第一增量小的整数作为第二增量,重复上述操作…
2>当增量的大小减到1时,就相当于整个序列被分到一组,进行一次直接插入排序,排序完成。
选择排序,即每次从待排序列中选出一个最小值,然后放在序列的起始位置,直到全部待排数据排完即可。
如何进行堆排序呢?
步骤如下:
1、将堆顶数据与堆的最后一个数据交换,然后对根位置进行一次堆的向下调整,但是调整时被交换到最后的那个最大的数不参与向下调整。
2、完成步骤1后,这棵树除最后一个数之外,其余数又成一个大堆,然后又将堆顶数据与堆的最后一个数据交换,这样一来,第二大的数就被放到了倒数第二个位置上,然后该数又不参与堆的向下调整…反复执行下去,直到堆中只有一个数据时便结束。此时该序列就是一个升序。
冒泡排序,该排序的命名非常形象,即一个个将气泡冒出。冒泡排序一趟冒出一个最大(或最小)值。
快速排序是公认的排序之王,快速排序是Hoare于1962年提出的一种二叉树结构的交换排序算法,其基本思想为:
任取待排序元素序列中的某元素作为基准值,按照该基准值将待排序列分为两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右序列重复该过程,直到所有元素都排列在相应位置上为止。
归并排序是采用分治法的一个非常典型的应用。其基本思想是:将已有序的子序合并,从而得到完全有序的序列,即先使每个子序有序,再使子序列段间有序。
计数排序,又叫非比较排序。顾名思义,该算法不是通过比较数据的大小来进行排序的,而是通过统计数组中相同元素出现的次数,然后通过统计的结果将序列回收到原来的序列中。
该系列文章主要是记录下自己暑假这段时间的学习笔记,暑期也在实习,抽空学了很多,每个方面的知识我都会另起一篇博客去记录,每篇头部主要是另起博客的链接。
冒泡排序算法应该是大家第一个接触的算法,其原理都应该懂,但我还是想以自己的语言来叙述下其步奏:
按照计算时间复杂度的规则,去掉常数、去掉最高项系数,其复杂度为O(N^2)
冒泡排序及其复杂度分析
空间复杂度就是在交换元素时那个临时变量所占的内存
给定一个整数序列{6,1,2,3,4},每完成一次外层循环的结果为:
我们发现第一次外层循环之后就排序成功了,但是还是会继续循环下去,造成了不必要的时间复杂度,怎么优化?
冒泡排序都是相邻元素的比较,当相邻元素相等时并不会交换,因此冒泡排序算法是稳定性算法
插入排序是对冒泡排序的一种改进
插入排序的思想是数组是部分有序的,再将无序的部分插入有序的部分中去,如图:
(图片来自 这里 )
空间复杂度就是在交换元素时那个临时变量所占的内存
插入排序的优化,有两种方案:
文章后面会给出这两种排序算法
由于插入排序也是相邻元素的比较,遇到相等的相邻元素时不会发生交换,也不会造成相等元素之间的相对位置发生变化
其原理是从未排序的元素中选出最小值(最大值)放在已排序元素的后面
空间复杂度就是在交换元素时那个临时变量所占的内存
选择排序是不稳定的,比如 3 6 3 2 4,第一次外层循环中就会交换第一个元素3和第四个元素2,那么就会导致原序列的两个3的相对位置发生变化
希尔排序算是改良版的插入排序算法,所以也称为希尔插入排序算法
其原理是将序列分割成若干子序列(由相隔某个 增量 的元素组成的),分别进行直接插入排序;接着依次缩小增量继续进行排序,待整个序列基本有序时,再对全体元素进行插入排序,我们知道当序列基本有序时使用直接插入排序的效率很高。
上述描述只是其原理,真正的实现可以按下述步奏来:
希尔排序的效率取决于 增量值gap 的选取,这涉及到数学上尚未解决的难题,但是某些序列中复杂度可以为O(N 1.3),当然最好肯定是O(N),最坏是O(N 2)
空间复杂度就是在交换元素时那个临时变量所占的内存
希尔排序并不只是相邻元素的比较,有许多跳跃式的比较,难免会出现相同元素之间的相对位置发生变化,所以希尔排序是不稳定的
理解堆排序,就必须得先知道什么是堆?
二叉树的特点:
当父节点的值总是大于子结点时为 最大堆 ;反之为 最小堆 ,下图就为一个二叉堆
一般用数组来表示堆,下标为 i 的结点的父结点下标为(i-1)/2;其左右子结点分别为 (2 i + 1)、(2 i + 2)
怎么将给定的数组序列按照堆的性质,调整为堆?
这里以建立最小堆为示例,
很明显对于其叶子结点来说,已经是一个合法的子堆,所以做堆调整时,子节点没有必要进行,这里只需从结点为A[4] = 50的结点开始做堆调整,即从(n/2 - 1)位置处向上开始做堆调整:
由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN),二次操作时间相加还是O(N logN)。故堆排序的时间复杂度为O(N * logN)。
空间复杂度就是在交换元素时那个临时变量所占的内存
由于堆排序也是跨越式的交换数据,会导致相同元素之间的相对位置发生变化,则算法不稳定。比如 5 5 5 ,堆化数组后将堆顶元素5与堆尾元素5交换,使得第一个5和第三个5的相对位置发生变化
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
快速排序在应该是大家经常看到、听到的算法,但是真正默写出来是有难度的。希望大家看了下面 挖坑填数 方法后,能快速写出、快速排序。
其原理就这么几句话,但是现实起来并不是这么简单,我们采取流行的一种方式 挖坑填数分治法
对于序列: 72 6 57 88 60 42 83 73 48 85
数组变为: 48 6 57 88 60 42 83 73 88 85
再重复上面的步骤,先从后向前找,再从前向后找:
数组变为: 48 6 57 42 60 72 83 73 88 85
可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了
空间复杂度,主要是递归造成的栈空间的使用:
快速排序的优化主要在于基准数的选取
快速排序也是跨越式比较及交换数据,易导致相同元素之间的相对位置发生变化,所以快速排序不稳定
前面也说了二分查找排序是改进的插入排序,不同之处在于,在有序区间查找新元素插入位置时,为了减少比较次数提高效率,采用二分查找算法进行插入位置的确定
具体步骤,设数组为a[0…n]:
二分查找插入位置,因为不是查找相等值,而是基于比较查插入合适的位置,所以必须查到最后一个元素才知道插入位置。
二分查找最坏时间复杂度:当2^X>=n时,查询结束,所以查询的次数就为x,而x等于log2n(以2为底,n的对数)。即O(log2n)
所以,二分查找排序比较次数为:x=log2n
二分查找插入排序耗时的操作有:比较 + 后移赋值。时间复杂度如下:
二分查找排序在交换数据时时进行移动,当遇到有相等值插入时也只会插入其后面,不会影响其相等元素之间的相对位置,所以是稳定的
白话经典算法排序
冒泡排序选择排序
快速排序复杂度分析
优化的插入排序
欢迎分享,转载请注明来源:优选云