话不多说,小知识先走一波
小知识
如何不使用额外变量完成数组不同位置值的交换?
代码:
/**
* 不使用第三个变量,交换数组不同的数值
* @param arr
* @param x
* @param y
*/
public static void swap(int arr[], int x, int y) {
arr[x] = arr[x] + arr[y];
arr[y] = arr[x] - arr[y];
arr[x] = arr[x] - arr[y];
}
注:在数组这样做有些地方会出现bug,比如快排中,数组0位置和其自身交换会变成0
选择排序:
/**
* 选择排序
* 基本思想:为每一趟从待排序的数据元素中选择最小(或最大)的一个元素作为首元素(交换位置),
* 直到所有元素排完为止,简单选择排序是不稳定排序
* @param arr
*/
public static void selectSort(int arr[]) {
int min;
for (int i = 0; i < arr.length -1; i++) {
min = arr[i];
for (int j = i + 1; j < arr.length; j++) {
if(min > arr[j]) {
swap(arr, i, j); //存在很多次交换,浪费时间
}
min = arr[i]; //不可缺少,arr[i]值改变了,不代表min改变
}
}
}
/**
* 改进:在算法实现时,每一趟确定最小元素的时候会通过不断地比较交换来使得首位置为当前最小,
* 交换是个比较耗时的操作,在还未完全确定当前最小元素之前,这些交换都是无意义的。
* 通过设置一个变量min,每一次比较仅存储较小元素的数组下标,
* 当轮循环结束之后,那这个变量存储的就是当前最小元素的下标,此时再执行交换操作即可
* @param arr
*/
public static void selectSortImprove(int arr[]) {
for (int i = 0; i < arr.length - 1 ; i++) {
int min = i;
for (int j = i + 1; j < arr.length ; j++) {
if(arr[min] > arr[j]) {
min = j;
}
}
//不相等表明数组后面有数比第一个位置值小
if(i != min) {
swap(arr, min, i);
}
}
}
冒泡排序
/**
* 冒泡排序
* 稳定排序
* @param arr
*/
public static void bubbleSort(int arr[]) {
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]) {
swap(arr, j, j + 1);
}
}
}
}
/**
* 冒泡排序改进版
* 在外层循环过程中,某次循环没有交换元素,证明后续元素有序
* @param arr
*/
public static void bubbleSortImprove(int arr[]) {
for (int i = 0; i < arr.length - 1 ; i++) {
boolean flag = true; //设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已然完成。
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
flag = false;
}
}
if(flag) {
break;
}
}
}
插入排序
/**
* 直接插入排序
* 从第一个元素开始,每次保证n个元素有序,否则交换
* 在一个有序集合中,找到要插入元素的位置,将该元素放在数组末尾,与前面相邻元素比较,即可找到合适位置
* @param arr
*/
public static void insertSort(int arr[]) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0 ; j--) { //以要插入的元素逆着遍历,交换位置
if(arr[j] < arr[j-1]) {
swap(arr, j, j-1);
}
}
}
小结
三大基础排序思路很简单,但是能否在极短时间内写出正确代码呢?
同时他们的时间复杂度都是O(n^2)