简单排序算法总结
最近打球受了点小伤,趁着养伤无聊,写点小算法的总结。今天的算法分别是冒泡排序、优化冒泡排序、选择排序、直接插入排序。想想如果以后我们逛淘宝的时候没有按销售量或者按价格排序这一选项,那么你的购物是多么不方便啊,你要是个不在乎money的人也罢了,可对于那些学生党来说那就不好办了。好了,闲话不多说,咱们进入主题(由java实现)
1.冒泡排序
冒泡排序的精髓是两两比较,大的后移,这样的好处是当每一次内循环结束后排在数组最后面的值是内循环中比较的最大值,由于这种排序最经典,因此不作过多介绍,代码实现如下:
for (int i = 1; i <= arr.length; i++)
for (int j = 0; j < arr.length - i; j++) {
//精髓就是每一次内部循环都是两两比较,大的往后移,这样每次循环后都能确保后面元素为最大值
if (arr[j + 1] < arr[j]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
2.优化冒泡排序
想想冒泡排序的代码和思想已经够简便明了了,为啥还要来个优化冒泡排序呢,怎么优化呢?大家思考一个问题,倘若需要我们排序的数据元素是这样的{2,1,3,4,5}(当然这个太简单,只是让大家有个概念),也就是说当你经过一次内循环后,数据就已经是从小到大排序了,你还需要再经过内、外循环再次进行两两比较,交换吗?显然这是浪费时间和资源的,于是我们可以引入一个标志(flag)用来判断还需不需要进行后面的循环。
boolean flag = true;//引入判断标志,放入外循环内
for (int i = 1; (i <=arr.length) && flag; i++) {
//先设置为false,一旦内循环一次都没有进行交换说明,此时的数组不需要排序
//那么下次就不用再进行循环判断了
flag = false;
for (int j = 0; j < arr.length - i; j++) {
if (arr[j + 1] < arr[j]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
//只要你经过交换,就说明你这个数组还没排序好,跟标志说你还要排序
//所以将标志位设置为true
flag = true;
}
}
}
3.选择排序
选择的排序思想是每当一次内循环后,都将当前比较的数据元素中最小的放到最前面,就好比现在一个老师他需要帮班级里10名同学排座位,老师需要比较同学的身高,根据高矮顺序安排座位(当然送礼的咱们不考虑),怎么比较呢?老师先让这些同学站好队,当然站队顺序随便,不分高矮,他先指定第一名同学小明出列,依次和后面同学比较,只要比小明矮的就和小明交换位置,剩下的规则也是这样,这样当第一次比较到第十名同学时,出列的那位同学一定是这10个同学里面最矮的,所以他应当坐在第一排,安排好第一名同学后老师就要安排剩下9名同学了,那么规则如何呢?当然和原来10人的规则一样啦,毕竟是个循环嘛。
int min = 0, temp = 0;
for (int i = 0; i < arr.length; i++) {
//先假设第一个元素是最小的
min = i;
for (int j = i; j < arr.length; j++) {
if (arr[min] > arr[j])
//只要比最小的还小那就记录下来
min = j;
}
if (i != min) {
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
4.直接插入排序
直接插入的排序其实就和我们日常打牌一样,我们日常打牌时是怎么理牌的?是不是把后面较小的牌插到前面位置上,这样才能组成顺子嘛,他的精髓其实也是两两比较,后者比前者小的就有向前插的资格,至于向前插在哪,那就是内循环做的事了,就好比我们这张牌要插在一个比他大的数和一个比他小的数之间,内循环的作用就是如此。
int flag = 0, i, j;
for (i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
// 设置一个哨兵,为了控制后面后移步数
flag = arr[i + 1];
for (j = i; (j >= 0) && (arr[j] > flag); j--) {
// 后移
arr[j + 1] = arr[j];
}
//把标志插到该插的位置
arr[j + 1] = flag;
}
}