排序算法
排序算法众所周知的比较简单,因此就在这里用一篇文章进行描述一下。
排序算法常用的有两种,一个是冒泡排序,一个是插入排序。
冒泡排序
假设我们有一个数组{1,5,7,9,2,4,8}。
所谓冒泡,就是不断地用前一个元素和后一个元素进行比较,如果满足条件就不处理,不满足条件,则会向气泡一样,不断地向后冒。
比如我们数组中的第一个和第二个元素比较,1<5,不做处理。此时数组{1,5,7,9,2,4,8}
然后我们再比较第二个和第二个元素,5<7,不做处理。此时数组{1,5,7,9,2,4,8}
……
我们再比较第四个和第五个元素,9>2,此时需要将9和2调换位置,数组变成{1,5,7,2,9,4,8}
……
以此类推,由于我们数组中9是最大值,因此它会不断地和后面的元素进行交换位置,就像气泡一样,不断地向后冒。最终的数组变成{1,5,7,2,4,8,9}
这时候我们进行了第一遍的循环,得出了数组中的最大元素9。然后我们再对数组的0到length-2重复比较,以此类推可以得出数组中第二大的元素。第一次的循环长度是从0到6,第二次的循环长度只要从1到5。以此类推第三次我们可以得出数组中第三大的元素,循环长度只要从1到4。第四次是1到3,第五次是1到2。由此,我们的整个数组的排序结束。
总结:
假设有一个长度为n的数组,
第一次从第0位与第1位的比较开始,一直比较到它的第n-2位与n-1位。
第二次从第0位与第1位的比较开始,一直比较到它的第n-3位与n-2位。
……
第n-1次从第0位与第1位的比较开始,一直比较到它的第n-1-(n-1)位与n-(n-1)位。即第0位与第1位。
由此排序结束,一共执行了n-1次循环,得出排序后的数组。
代码实现:
public int[] sort(int[] ints) { int n = ints.length; // 一共会执行n-1次循环。 for (int i = 0; i < n - 1; i++) { // 每次循环从第0位与第一位比较开始,一直比较到第n-1-(n-1)与第n-(n-1)的比较。这里的i=n-1 for (int j = 0; j < n - 1 - i; j++) { //如果前一个数大于后一个数,则交换位置。否则不变 if (ints[j] > ints[j+1]) { int tmp = ints[j+1]; ints[j + 1] = ints[j]; ints[j] = tmp; } } } return ints; }
客户端调用代码
public static void main(String[] args) { int[] ints = {1,5,7,9,2,4,8}; Main4 m = new Main4(); m.sort(ints); System.out.println(StringUtils.join(ints,',')); }
输出结果:
1,2,4,5,7,8,9
插入排序
插入排序同样也是用前一个元素和后一个元素不断地进行比较,如果满足条件,则不进行处理,不满足条件,就将当前元素和前面的每一个元素进行比较,找到可以插入的位置后将元素插入,并将后面的元素后移一位。
假设我们有一个数组{1,5,7,9,2,4,8}。
第一次比较,1<5,不作处理。
第二次比较,5<7,不作处理。
……
第四次比较,9>2,提出元素2出来,与前面的三位再逐一比较。
第4.1次比较,1<2,不作处理。
第4.2次比较,5>2,因此将元素2放在元素2的位置上,同时后面的元素5,7,9全部后移一位。此时数组{1,2,5,7,9,4,8}
第五次比较,9>4,提出元素4出来,再与前面的4位逐一比较。
第5.1次比较,1<4,不作处理。
第5.2次比较,2<4,不作处理。
第5.3次比较,5>4,因此将元素4放在元素5的位置上,同时后面的元素5,7,9全部后移一位。此时数组{1,2,4,5,7,9,8}
第六次比较,9>8,提出元素8出来,再与前面的5位进行比较。最后可得出数组{1,2,4,5,7,8,9}
总结:
一个长度为n的数组,从第一位与第二位比较开始,一直到第n-2位与n-1位比较结束,一共会比较n-1次。其间如果判断出元素i大于元素i+1,则会元素i+1与前面的0到i位元素依次比较,找到第一个大于元素i+1的元素位置m,将元素i+1存放在m,同时对m到i位置上元素后移一位。
代码实现:
public int[] sort2(int[] ints) { int n = ints.length; // 一共要循环比较n-1次 for (int i = 0; i < n - 1; i++) { // 如果第i个数比第i+1个数大,则将i+1与前面0到i位上的数进行比较。 if (ints[i] > ints[i + 1]) { // 从0开始,一直比较到i。 for (int j = 0; j <= i; j++) { // 如果遇见了比i+1位上的数大的位置j,将i+1位上的元素存放在j位上,同时对j到i位的元素依次后移一位 if (ints[j] > ints[i + 1]) { int tmp = ints[i + 1]; // 对j到i位上的依次后移。这里是倒着移动。 for (int k = i; k >= j; k--) { ints[k + 1] = ints[k]; } // 移动完成后,将第i+1位元素存放在j位上。并跳出循环。继续进行最外面的n-1次循环比较。 ints[j] = tmp; break; } } } } return ints; }
客户端调用
public static void main(String[] args) { int[] ints = {1,5,7,9,2,4,8}; Main4 m = new Main4(); m.sort2(ints); System.out.println(StringUtils.join(ints,',')); }
输入结果:
1,2,4,5,7,8,9
二分法
二分法用来在有序数组中快速地查找某一个元素的位置。每一次可以去除掉一半的元素。
假如有数组int[] ints={1,2,4,5,7,8,9},长度为7。
我们要从中找到元素7的位置。
第一次我们取数组的中间元素(0+6)/2=3,ints[3]=5。判断5<7,得出7所在的位置大于3。去除掉数组的左半部分。剩余{1,2,4,5,7,8,9}
第二次再取中间元素(3+1+6)/2=5,int[5]=8。判断8>7,得出7所在的位置小于5。这时候,结合两次判断的范围,得出7的取值大于3,小于5,因此就只剩下位置4。
返回7所在的位置下标:4
结论:
我们假设有一个有序数组,长度为n。求它的某一个元素的值。每一次去掉可选范围的一半。最多会计算log(n)次。
代码实现:
public int search(int[] ints, int num) { int tmp = -1; int begin = 0; int end = ints.length; int middle = 0; while (begin < end) { middle = (begin + end) >> 1; if (num == ints[middle]) { return middle; } else if (num < ints[middle]) { // 范围在左边,取左部分数组 end = middle - 1; } else { // 范围在右边,取右部分数组 begin = middle + 1; } } if (num == ints[begin]) { return begin; } return tmp; }
客户端调用
public static void main(String[] args) { int[] ints = {1,5,7,9,2,4,8}; Main4 m = new Main4(); // 先会数组排序 m.sort2(ints); System.out.println(StringUtils.join(ints,',')); // 查找元素1的位置 System.out.println(m.search(ints, 1)); // 查找元素2的位置 System.out.println(m.search(ints, 2)); }
输出结果:
0,1