1.冒泡排序 O(n2)
基本思路:在要排序的一组数中,从第一个元素开始,依次对比当前元素和下一个元素,让较大的数往后沉,较小的数往前冒。即当发现相邻的两个数和排序的要求相反时,就交换它们的位置。
int[] arr = {5,8,2,4,9,1,3,6,7};
// 1. 冒泡排序。外层循环控制循环次数,内层循环比较数据
@Test
public void fun () {
for(int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j] > arr[j+1] ) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
out();
}
// 冒泡排序优化
@Test
public void fun1() {
boolean flag;
for(int i = 0; i < arr.length-1; i ++) {
// 标识,用来判断数组是否发生了交换
flag = false;
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j] > arr[j+1] ) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = true;
}
}
// 当一轮下去之后,数组未发生任何交换,则表示排序已经完成
if (!flag) {
break;
}
}
}
2.快速排序
基本思想:选择一个基准元素a(通常找第一个元素),目标是让a左边的元素都小于a,右边的元素都大于a。具体方法是:从数组两端开始探测,左边初始为哨兵i,右边为哨兵j。从左往右依次找一个大于基准数a的数,从右往左依次找一个小于基准数a的数,交换它们。当两个哨兵相遇,交换哨兵所在位置的元素和基准数,一次探测结束。接着对左右两边分别进行探测,直至排序完成。右边的哨兵要先探测,因为左哨兵所在位置是的元素是小于基准数的,而当最终左右哨兵相遇的时候需要将基准数和哨兵所在位置交换,因此这时候交换的数应该是小于基准数的,即满足基准数左边的元素都小于它。
int[] arr = {5,8,2,4,9,1,3,6,7};
@Test
public void fun2() {
int low = 0; // 左哨兵位置,从左向右寻找小于基准数的数
int high = arr.length - 1; // 右哨兵位置,从右向左寻找大于基准数的数
quickSort(low, high);
out();
}
// 2.快速排序---哨兵法
private void quickSort(int low, int high) {
if(low>high){
return;
}
int tmp = arr[low]; // 基准数
int i = low;
int j = high;
while (i < j) {
// 先移动右哨兵,依次往左递减
while (arr[j] >= tmp && i < j) {
j -- ;
}
// 再移动左哨兵,依次往右递增
while (arr[i] <= tmp && i < j) {
i ++ ;
}
// 交换
if (i < j) {
int flag = arr[i];
arr[i] = arr[j];
arr[j] = flag;
}
}
// 此时跳出循环,表明两个哨兵相遇,搜寻结束,交换基准数和哨兵所在位置
arr[low] = arr[i];
arr[i] = tmp;
// 对基准数左边进行排序,基准数位置现在在j和i
quickSort(low, j - 1);
// 对右半边进行排序
quickSort(j + 1, high);
}
// 快速排序,填坑法
public void quickSort2(int low, int high) {
while(low > high) {
return;
}
int i = low;
int j = high;
int tmp = arr[low]; // 挖出arr[low]记为基准数,这是一个坑
while(i < j) {
// 从右向左寻找比基准数tmp小的数,找到后填补arr[low]的坑,这时arr[j]变为新的坑
while(i < j && arr[j] >= tmp) {
j--;
}
// 跳出循环,说明找到比基准数小的数了
if (i < j) {
arr[i] = arr[j];
i++;
}
// 从左向右寻找比基准数大的数,找到后填补arr[j]的坑,这时arr[i]变为新的坑
while(i < j && arr[i] <= tmp) {
i++;
}
if (i < j) {
arr[j] = arr[i];
j--;
}
}
//循环结束,表明i和j相遇,将最后一个坑填上
arr[i] = tmp;
quickSort2(low, i - 1);
quickSort2(i + 1, high);
}
3.选择排序 O(n2)
基本思想:在长度为n的数组中,第一次遍历n-1个数,找到最小的数与第一个元素交换;第二次遍历n-2个数,找到最小的值与第二个元素交换... ...
/
/ 选择排序
@Test
public void fun8() {
int tmp;
// 最后一个元素不需要再对其进行一次排序,因为前面的元素已经完成了排序,则最后一个元素必定已排序过
for(int i = 0; i < arr.length - 1; i++) {
int index = i;
// 这里需要对i之后的所有元素都比较一下,防止有漏掉的
for (int j = i; j < arr.length; j++) {
if (arr[j] < arr[index]) {
index = j;
}
}
if (index != i) {
tmp = arr[i];
arr[i] = arr[index];
arr[index] = tmp;
}
}
out();
}
4.插入排序 O(n2)
基本思想:在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是有序的。如此反复循环,直到全部排好序。
相同的场景
//插入排序
@Test
public void fun13() {
for(int i = 1; i < len; i++) {
for(int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
int tmp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = tmp;
}
}
}
out();
}
5.希尔排序
基本思想:这个排序又称为缩小增量排序。设待排序数组长度为n,取一个整数index(小于n)作为间隔将数组分为index个子序列,所有距离为index的元素放在一个子序列中,对每一个子序列分别进行直接插入排序。然后缩小index,重复上述子序列划分和排序工作。直至最后取到index=1将所有元素放在一个序列中进行排序。 由于开始时,index的取值比较大,每一个序列中的元素比较少,因此排序速度很快。到后面index逐渐增大,子序列中元素个数增加,但由于前面的工作基础,大多数元素已经是有序状态,所以排序速度依然很快。
// 希尔排序
@Test
public void fun14() {
int index = len;
while(true) {
index = index/3 + 1; // 增量,每次在当前增量的基础上除3再加1
for(int i = 0; i < index; i++) { // 根据增量进行分组,一共分为index个组
for(int k = i+index; k < len; k+=index) { // 进行插入排序
for(int j = k; j > i; j-=index){
if (arr[j] < arr[j - index]) {
int tmp = arr[j];
arr[j] = arr[j-index];
arr[j-index] = tmp;
}
}
}
}
if (index == 1) {
break;
}
}
out();
}
参考博客:https://www.runoob.com/w3cnote/sort-algorithm-summary.html
https://www.jianshu.com/p/40dcc3b83ddc
来源:oschina
链接:https://my.oschina.net/u/4359745/blog/3424585