一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
前言
排序算法算是计算机科学中经常被研究使用的基础知识点。例如有序数组通过从小到大或者从大到小的规则有序排列,如何将无序数组变成有序数组的过程并以高效排序形式完成是本次需要学习内容。
冒泡排序
冒泡排序作为一种基础排序算法,也是常常被提起的入门算法了。
| 索引0 | 索引1 | 索引2 | 索引3 | 索引4 | 索引5 |
|---|---|---|---|---|---|
| 2 | 1 | 5 | 3 | 4 | 7 |
- 例如一个初始无序数组,首先会指向
索引0和索引1来比较两者大小,若索引0比索引1大则两者交换位置。
| 索引0 | 索引1 | 索引2 | 索引3 | 索引4 | 索引5 |
|---|---|---|---|---|---|
| 1 | 2 | 5 | 3 | 4 | 7 |
- 接着继续指向
索引1和索引2,比较索引1比索引2的大小并根据以上规则判断两者是否需要交换位置。 - 之后步骤同上执行
- 最终轮回直到指向最后
索引4和索引5比较后结束排序算法过程。最后得到的数组结果就是从小到大的有序数组了。
原理
冒泡排序的过程其实就是在每次轮回中将未排序的值最大向后推进。 直接通过实战排序来看冒泡排序过程会更直观,例如一下数组数据进行如上介绍的排序方式执行算法。
| 4 | 2 | 1 | 6 | 5 | 3 |
|---|
通过第一轮排序之后会发现数组中最大值6已经到达数组尾部,因此通过一轮排序可以在数组中筛选出最大值。
紧接着进行第二轮第三轮...直到最终轮回结束。
算法代码
简单算法
i表示轮回次数,j用来表示指针来执行比较次数。
void main(){
int[] datas;
for(int i=0;i<datas.length - 1;i++){
for(int j=0;j<datas.length - 1;j++){
if(datas[j] > datas[j+1]){
int temp = datas[j];
datas[j] = datas[j+1];
datas[j+1] = temp;
}
}
}
}
假设N个数据执行以上算法 可推导出大O记法为O()。
优化算法
通过增加sorted标记位跳过后续若没有做排序替换直接跳过循环以及减少j循环次数来减少步数,避免掉一些不必要的循环次数。
void main(){
int[] datas;
boolean sorted = true;
for(int i=0;i<datas.length - 1;i++){
for(int j=0;j<datas.length-i - 1;j++){
if(datas[j] > datas[j+1]){
sorted = false;
int temp = datas[j];
datas[j] = datas[j+1];
datas[j+1] = temp;
}
}
if(sorted) break;
}
}
假设N个数据执行以上算法 可推导出大O记法为O()。 虽然好似对算法进行了优化处理,但从大数据趋势发展上看大O记法上看还是比较低效的算法形式。
- 不过要知道大O记法还有最好情况和最长情况,如上算法就是对最好情况优化,在特定情况下还是可以提升效率。
- 追求最佳情况下的算法还是特别有必要,多考虑各种情况有效避免步数冗余。如上最优情况时间复杂度可以是O(N)
- O()被记作二次时间是比较差劲的,期望上最好是向着O(N)线性发展最好了。