目录
直接插入排序
基本思想
直接插入排序的基本思想是:将数组中的所有元素依次跟前面已经排好的元素相比较,如果选择的元素比已排序的元素小,则交换,直到全部元素都比较过为止。
算法描述
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
①. 从第一个元素开始,该元素可以认为已经被排序
②. 取出下一个元素,在已经排序的元素序列中从后向前扫描
③. 如果该元素(已排序)大于新元素,将该元素移到下一位置
④. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
⑤. 将新元素插入到该位置后
⑥. 重复步骤②~⑤
代码实现
提供两种写法,一种是移位法,一种是交换法。移位法是完全按照以上算法描述实,再插入过程中将有序序列中比待插入数字大的数据向后移动,由于移动时会覆盖待插入数据,所以需要额外的临时变量保存待插入数据,代码实现如下:
①. 移位法:
public static void sort(int[] a) {
if (a == null || a.length == 0) {
return;
}
for (int i = 1; i < a.length; i++) {
int j = i - 1;
// 先取出待插入数据保存,因为向后移位过程中会把覆盖掉待插入数
int temp = a[i];
// 如果待是比待插入数据大,就后移
while (j >= 0 && a[j] > temp) {
a[j+1] = a[j];
j--;
}
// 找到比待插入数据小的位置,将待插入数据插入
a[j+1] = temp;
}
}
而交换法不需求额外的保存待插入数据,通过不停的向前交换带插入数据,类似冒泡法,直到找到比它小的值,也就是待插入数据找到了自己的位置。
②. 交换法:
public static void sort2(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
for (int i = 1; i < arr.length; i ++) {
int j = i - 1;
while (j >= 0 && arr[j] > arr[i]) {
//只要大就交换操作
arr[j + 1] = arr[j] + arr[j+1];
arr[j] = arr[j + 1] - arr[j];
arr[j + 1] = arr[j + 1] - arr[j];
}
}
}
算法效率
直接插入排序不是稳定的排序算法。
平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 |
---|---|---|---|
O(n2) | O(n) | O(n2) | O(1) |
交换两个数方法
临时变量
思路简介:建立一个临时变量,通过temp=a,a=b,b=temp来实现交换。
缺点:这只是一种假交换,由于这只是在函数内部临时变量间的交换,所以当函数退出,函数栈帧被释放,原本的值并没有交换。
/**
* 临时变量法(引入一个中间值)
*
* @param a 1
* @param b 2
*/
private static void swapByTemp(int a, int b) {
int temp = a;
a = b;
b = temp;
// 2|1
System.out.println(" 临时变量法 交换后: 1--" + a + "|" + b);
}
算术法交换
思路简介:取两个数的和,然后通过减去另外一个数来得到这个数。
方法缺陷:两个数的和可能会越界。(数值小的时候可以用)。同样的这是一种假交换,函数调用结束后原本的值并没有真正的交换。
/**
* 通过算术法交换(可能溢出)
*
* @param a 110
* @param b 200
*/
private static void swapByArithmetic(int a, int b) {
// a == a + b 310
a = a + b;
// b== a + b - b == a, 此时b == a 310-200
b = a - b;
// a == a + b - a == b, 此时a == b 310-110
a = a - b;
System.out.println(" 通过算术法交换 交换后:" + a + "|" + b);
}
位运算交换
思路简介:通过二进制异或方法交换
/**
* 位运算
*
* @param a
* @param b
*/
private static void swapByBitOperation(int a, int b) {
a = a ^ b;
b = a ^ b;
a = a ^ b;
// 0|2
System.out.println(" 位运算 交换后:" + a + "|" + b);
}
}
参考代码
public class TwoNumberSwap { public static void main(String[] args) { int a = 110; int b = 200; System.out.println("1.临时变量法 交换前: " + a + "|" + b); swapByTemp(a, b); // 1|2(没有返回值还是以前的a、b) System.out.println(" 临时变量法 交换后 :2--" + a + "|" + b); int one = 2; int two = 0; //2|0 System.out.println("2.通过算术法交换 交换前:" + one + "|" + two); swapByArithmetic(one, two); int x = 110; int y = 200; System.out.println("3.位运算 交换前:" + x + "|" + y); swapByBitOperation(a, b); } /** * 临时变量法(引入一个中间值) * * @param a * @param b */ private static void swapByTemp(int a, int b) { int temp = a; a = b; b = temp; // 2|1 System.out.println(" 临时变量法 交换后: 1--" + a + "|" + b); } /** * 通过算术法交换(可能溢出) * * @param a * @param b */ private static void swapByArithmetic(int a, int b) { // a == a + b 310 a = a + b; // b== a + b - b == a, 此时b == a 310-200 b = a - b; // a == a + b - a == b, 此时a == b 310-110 a = a - b; System.out.println(" 通过算术法交换 交换后:" + a + "|" + b); } /** * 位运算 * * @param a * @param b */ private static void swapByBitOperation(int a, int b) { a = a ^ b; b = a ^ b; a = a ^ b; // 0|2 System.out.println(" 位运算 交换后:" + a + "|" + b); } }