比较器与桶排序
比较器
前面介绍的选择排序、冒泡排序、插入排序、归并排序、堆排序以及快速排序,还有选择排序的变种希尔排序、鸡尾酒排序,这些都是基于比较的排序。对于这些基于比较的排序,可以通过修改比较器,来达到比较其他非基本数据类型的比较。
如下图是一个比较器的实现:
如果返回一个负数,认为第一个参数应该排在前面;若返回正数,则第二个参数排在前面。所以我们经常可以看到下面的写法:
这里实现的是由大到小排序。
在C++中,比较器的实现就是重载运算符。
下面在举一个例子,将学生按年龄大小的顺序由小到大排序,如果年龄相同,按学号由小到大排列:
我们知道优先级队列的底层结构是小根堆,现在我们想要将其改为大根堆,也可以通过比较器实现。
但有一点需要注意,因为选择器是由我们自己实现的,要注意不能在比较的过程冲形成环,即自己设置的比较策略应该具有传递性。
如有a、b、c存在,设置a>b,b>c,c>a,该种比较策略是错误的。
桶排序
桶排序不是基于比较的排序,它只能用于对基本数据类型进行排序,只与具体业务有关。
1. 计数排序
某公司有员工10人,员工的年龄在20到50之间,请对员工的年龄进行排序。
用计数排序对员工进行排序:
1. 创建容器数组arr[50 - 20 + 1];
2. 依次统计每个年龄有多少人,即arr[0]储存20岁的员工有多少人,arr[1]存储21岁有多少人。。。。。。
按照数组arr的顺序依次输出每个年龄。
该算法的时间复杂度为O(N),额外空间复杂度为O(M)。
但需要注意的是,这里的要求是对员工的年龄进行排序,所以可以用计数排序。如果题目的要求是请依据年龄对员工进行排序,则不能使用计数排序。因为使用桶排序的前提是需要构造出容器来存储要排序的数据类型。
另外,如果要排序的数字的最小值与最大值之间相差太大,也不适合使用桶排序。
2. 基数排序
使用基数排序的算法进行排序时,需要经过以下几个步骤:
1. 选出最大的一个数字,判断它是几位数,并将其余数字补至最高位。
2. 准备10个桶[0 ,9]。
3.根据各位数字个位的值依次将每个数字装入桶中。
4. 从左到右依次将桶中的数字倒出。
5.根据各位数字十位的值依次将每个数字装入桶中。
6.重复上述过程,直到最高位。
基数排序的时间复杂度应为O(N*K),其中k是最大数字的位数,一般k的数值不会很大,所以可以将该算法的时间复杂度看作O(N)。