一直都有写技术博客的想法,以前由于储备知识不够,一直没写。如今在女朋友的支持下,开始尝试写写技术博客,就当方便自己查找的工具贴吧。好了,废话不说了,上干货。
排序算法大体分为5大类:选择排序,插入排序,交换排序,归并排序,基数排序
一.交换排序(冒泡排序+快速排序)
1.冒泡排序
冒泡排序的核心思想就是将权重轻的气泡上升到序列最前(对于升序排列),而对于降序排列则反之。
由于使用java写的,所以要使用到java当中的一些特性,比如泛型和比较类
根据比较类comparator来判断是升序排列还是降序排列,comparator中的compare函数返回a > b ? 1 : (a < b ? -1 : 0),是升序排列,返回a > b ? -1 : (a < b ? 1 : 0),则是降序排列
冒泡排序的基本思路是:
①假定整个数组都是无序区域
②无序区域第一个气泡一次和后续气泡进行比较
③不满足排序规则的气泡,则让两个气泡交换位置
④一趟遍历过后,有序区域出现一个气泡,无序区域还剩下n-1个气泡
⑤重复①~④步骤
public static <T> void bubbleSort(T[] t, Comparator<? super T> comparator) {
int size = t == null ? 0 : t.length;
T temp = null; // 用于记录临时数据
for(int i = 0; i < size - 1; i++) {
for(int j = i + 1; j < size; j++) {
// 交换两个数的位置
if(comparator.compare(t[i], t[j]) > 0) {
temp = t[i];
t[i] = t[j];
t[j] = temp;
}
}
}
}
时间复杂度:O(n^2)
空间复杂度:O(1)
二.快速排序
快速排序主要用到了分治法的基本思想,分治法就是将一个原问题分解成几个规模更小但是结构和原问题相似的子问题,然后递归解决。
根据比较类comparator来判断是升序排列还是降序排列,comparator中的compare函数返回a > b ? 1 : (a < b ? -1 : 0),是升序排列,返回a > b ? -1 : (a < b ? 1 : 0),则是降序排列
快速排序基本思路:
① 选择第一个数为基准值
②从左到右遍历,遍历到第一个比基准值大的数为止
③从右向左遍历,遍历到第一个比基准值小的数为止
④步骤②和步骤③所在的元素进行交换
⑤重复②~④,这样的得出过结果是一侧是全比基准点小的元素,一侧是全比基准点大的元素
⑥对两侧元素分别进行递归计算
public static <T> void quickSort(T[] t, int start, int end, Comparator<? super T> comparator) {
if (start < end) {
T base = t[start]; // 选定的基准值(第一个数值作为基准值)
T temp; // 记录临时中间值
int i = start, j = end;
while(i < j) {
while((comparator.compare(t[i] ,base) < 0) && (i < end)) {
i++;
}
while((comparator.compare(t[j], base) > 0) && (j > start)) {
j--;
}
if(i <= j) {
temp = t[i];
t[i] = t[j];
t[j] = temp;
i++;
j--;
}
}
if(start < j) {
quickSort(t, start, j, comparator); // 对低字段表进行递归排序
}
if(end > i) {
quickSort(t, i, end, comparator); // 对高字段表进行递归排序
}
}
}
空间复杂度:O(log2n)
测试一下算法的性能吧,选用不同的排序算法对程序整体的性能影响还是挺大的。
首先需要打乱已知数组的顺序
思路:
①假定已知数组是一个有序序列
②随机一个有序序列的索引,该所在的元素和有序序列最后一个元素交换
③有序序列的最后一个元素加入到无序序列中
④重复①~③
时间复杂度:O(n)
空间复杂度:O(1)
public static <T> void disturbOrder(T[] t) {
int size = t == null ? 0 : t.length;
if(size != 0) {
int randCount = 0; // 索引
int position = 0; // 当前位置
T temp;
do {
Random rand = new Random();
int r = size - randCount;
position = rand.nextInt(r);
randCount++;
// 将随机出的索引所在的位置的数据和r位数据进行交换
temp = t[position];
t[position] = t[r - 1];
t[r - 1] = temp;
} while (randCount < size);
}
}
简单写个测试程序
public static void main(String[] args) {
Integer[] numbers = new Integer[10000];
for(int i = 0; i < numbers.length; i++) {
numbers[i] = i;
}
disturbOrder(numbers);
long start = System.currentTimeMillis();
quickSort(numbers, 0, numbers.length - 1, new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a > b ? 1 : (a < b ? -1 : 0);
}
});
long end = System.currentTimeMillis();
System.out.println("快速排序耗时:" + (end - start));
disturbOrder(numbers);
long start1 = System.currentTimeMillis();
bubbleSort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a > b ? 1 : (a < b ? -1 : 0);
}
});
long end1 = System.currentTimeMillis();
System.out.println("冒泡排序耗时:" + (end1 - start1));
}
控制台打印结果:
快速排序耗时:43ms
冒泡排序耗时:225ms