-
数组排序(优化)
基本思路
-
冒泡排序
n个数字来排序,相邻元素俩俩比较,小(或者大)靠前
总共比较 n- 1 轮, 每轮比较 n-1-i 次
冒泡排序:简记为 两个 for 循环,一个 if 循环;
第一个for循环控制 比较轮数
第二个for循环控制 每轮的比较次数
if循环控制 条件
-
冒泡排序的优化方法
原来普通的冒泡排序它每个元素每次都要进行比较(拿降序来看),比如 f,g,d,c,e,b,a 这几个字母,f 要和 g 比较,f < g ,f 和 g 交换位置,然后 f又和 d 比较,……,b 要和 a 比较,b > a ,b 和 a 不交换位置总共进行 n-1 轮比较,每轮比较进行 n-1-i 次比较,总共需要比较 21 次
【橙色为正在进行比较的元素】
【若满足交换条件,蓝色标注交换后位置】
【紫色表示交换后固定位置,不进行下一轮比较】
普通冒泡排序过程 比较轮数(n=7,
n-1=7-1=6,总共比较6轮)
i 每轮比较次数
(n-1-i 次)
f,g,d,c,e,b,a
排序过程及结果
1 0 6 f,g,d,c,e,b,a <==> g,f,d,c,e,b,a
g,f,d,c,e,b,a <==> g,f,d,c,e,b,a
g,f,d,c,e,b,a <==> g,f,d,c,e,b,a
g,f,d,c,e,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
2 1 5 g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
3 2 4 g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
4 3 3 g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
5 4 2 g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
6 5 1 g,f,e,d,c,b,a <==> g,f,e,d,c,b,a 总共比较了 6+5+4+3+2+1 = 21 次
优化冒泡排序过程 比较轮数(n=7,
n-1=7-1=6,总共比较6轮)
i 每轮比较次数
(n-1-i 次)
f,g,d,c,e,b,a
排序过程及结果
是否有序
1 0 6 f,g,d,c,e,b,a <==> g,f,d,c,e,b,a
g,f,d,c,e,b,a <==> g,f,d,c,e,b,a
g,f,d,c,e,b,a <==> g,f,d,c,e,b,a
g,f,d,c,e,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
否 2 1 5 g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,d,e,c,b,a
g,f,d,e,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
g,f,e,d,c,b,a <==> g,f,e,d,c,b,a
【第二轮比较结束】
[g,f,e,d,c,b,a有序了,结束比较]
[直接出结果 g,f,e,d,c,b,a]
是 总共比较了 6+5 = 11 次
为了使运行不那么繁琐,比较次数可以更少,运行更快一点,我们就有了冒泡排序的优化方法,还是拿降序来看,比如 f,g,d,c,e,b,a 这几个字母,f 要和 g 比较,f < g ,f 和 g 交换位置,然后 f又和 d 比较,……,每轮比较一轮后都会返回去看看数字排序是否有序,若有序,就直接退出循环,从而减少了比较次数
代码实现
package 数组常见算法总结;
import java.util.Arrays;
public class MaoPao {
public static void main(String[] args) {
// 定义一个int类型的数组ns
int[] ns = { 23, 18, 79, 46, 35 };
// 为方便更直观的观察升序后结果,这里输出一下原数组ns
System.out.println("原数组ns为:" + Arrays.toString(ns));
// 冒泡排序(按升序排列)
for (int i = 0, n = ns.length; i < n - 1; i++) {// 比较n-1轮
for (int k = 0; k < n - 1 - i; k++) {// 每轮比较n-1-i次
// 相邻比较
if (ns[k] > ns[k + 1]) {// 当满足 ns[k]>ns[k+1] 条件时,
// 会ns[k]和ns[k+1]交换位置 ,大数字交换到右边,从而形成升序排列
// <<如果想要进行降序排列,只需要将if(ns[k]>ns[k+1])中 > 改为 < 即可>>
// 三次异或可以进行两元素的交换
ns[k] = ns[k] ^ ns[k + 1];
ns[k + 1] = ns[k] ^ ns[k + 1];
ns[k] = ns[k] ^ ns[k + 1];
}
}
}
System.out.println("ns升序排序结果为:" + Arrays.toString(ns));
//===========================================================================
// 冒泡排序的优化算法
// 定义一个String类型的数组array
String[] array = { "f", "g", "d", "c", "e", "b", "a" };
// 为方便更直观的观察排序后结果,这里输出一下原数组array
System.out.println("原数组array为:" + Arrays.toString(array));
int counter = 0;// 我们用counter记录下比较次数
// 冒泡排序的优化算法(这个我们看看降序排列结果吧)
for (int i = 0, n = array.length; i < n - 1; i++) {// 比较n-1轮
// 这里先看看整个的排列是否处于有序状态
// true 表示有序,false 表示无序
boolean isSorted = true;
for (int k = 0; k < n - 1 - i; k++) {// 每轮比较n-1-i次
counter++;
// 相邻比较
if (array[k].compareTo(array[k + 1]) < 0) {
// 若想升序排列,只要将这里的 < 改成 > 即可
// String类型不能通过异或操作交换元素,只能采用中间变量方法交换元素
String stem = array[k];// 将array[k]赋值给中间变量
array[k] = array[k + 1];
array[k + 1] = stem;
isSorted = false;
}
// 如果排列有序,结束for循环
if (isSorted) {
break;
}
}
}
System.out.println("冒泡排序的优化算法总共比较了" + counter + "次");
System.out.println("array降序排序结果为:" + Arrays.toString(array));
}
}
运行结果
原数组ns为:[23, 18, 79, 46, 35]
ns升序排序结果为:[18, 23, 35, 46, 79]
原数组array为:[f, g, d, c, e, b, a]
冒泡排序的优化算法总共比较了11次
array降序排序结果为:[g, f, d, e, c, b, a]
-
无序数组查找
基本思路
-
遍历查找
通过一个下标,从数组头元素(或尾元素)开始对该数组进行遍历,将数组中每个元素与指定元素进行比较,从而确定数组中是否存在该指定元素
-
双指针遍历查找
通过两个下标,分别从数组头元素和尾元素同时开始对该数组进行遍历,将数组中每个元素与指定元素进行比较,从而确定数组中是否存在该指定元素
代码实现
-
遍历查找代码实现
package 数组常见算法总结;
public class Find1 {
public static void main(String[] args) {
// 整型数组
// 定义一个int类型数组ns
int[] ns = { 1, 3, 5, 7, 9 };
// 指定元素targe1 = 3(该数组中存在);
int targe1 = 3;
// 目标元素下标默认为-1,代表不存在
int index = -1;
// 遍历查找
for (int i = 0; i < ns.length; i++) {
if (ns[i] == targe1) {
index = i;
break;
}
}
System.out.println("3存在于数组ns的下标为:" + index);
//=====================================================
// 字符串数组
// 定义一个String类型数组name
String[] name = { "小乔", "大乔", "鲁班七号" };
// 指定元素targe2 = “王昭君”(该数组中不存在);
String targe2 = "王昭君";
// 目标元素下标默认为-1,代表不存在
int index1 = -1;
// 遍历查找
for (int i = 0; i < name.length; i++) {
//字符串等值判断用equals()方法
if (targe2.equals(name[i])) {
index1 = i;
break;
}
}
System.out.println("王昭君存在于数组name的下标为:" + index1);
}
}
-
双指针遍历查找代码实现
package 数组常见算法总结;
public class Find2 {
public static void main(String[] args) {
int[] ns = { 2, 4, 6, 8 };// 定义一个int类型数组
int targe = 6;// 定义指定元素为6
int index = -1;// 默认index为-1,表示不存在
//双指针查找
for (int i = 0, k = ns.length-1; i <= k; i++, k--) {
// 若指定元素与数组某一下标位置元素相等
// 则将该下标值赋给index
if (targe == ns[i]) {
index = i;
}
if (targe == ns[k]) {
index = k;
}
}
System.out.println("6在数组ns中存在的下标位置为; " + index);
}
}
运行结果
-
遍历查找运行结果
3存在于数组ns的下标为:1
王昭君存在于数组name的下标为:-1
-
双指针遍历查找运行结果
6在数组ns中存在的下标位置为; 2
-
有序数组查找(二分)
基本思路
二分查找法 (可以提高查找元素的效率)
二分查找法的过程:
1.对有序数组:先确定好它的低位元素下标,高位元素下标,从而确定范围
2.计算中位元素下标:中位元素下标=(低位元素下标+高位元素下标)/ 2
3.判断 中位元素 是否等于 指定元素
1)中位元素 = 指定元素 ,返回中位元素下标,查找成功,退出算法
2)中位元素 > 指定元素 ,取当前数组的前半段范围作为新的搜索数组
3)中位元素 < 指定元素 ,取当前数组的后半段范围作为新的搜索数组
代码实现
package 数组常见算法总结;
public class Find3 {
public static void main(String[] args) {
int[] ns = { 1, 3, 5, 7, 9 };// 定义一个int类型数组
int low = 0;// 定义低位下标
int high = ns.length - 1;// 定义高位下表
int target = 7;// 定义指定元素为7
int index = -1;// index默认-1,表示不存在
// 满足 low<=high 条件时,才可以进入循环
while (low <= high) {
// 定义中位下标
int mid = (low + high) / 2;
// 如果中间值正好等于指定元素,直接将下标赋予index
if (ns[mid] == target) {
index = mid;
break;
// 如果中间值小于指定元素,只取右半段
} else if (ns[mid] < target) {
low = mid + 1;
// 如果中间值大于指定元素,只取左半段
} else if (ns[mid] > target) {
high = mid - 1;
}
}
System.out.println("目标元素在有序数组中的下标位置为:" + index);
}
}
运行结果
目标元素在有序数组中的下标位置为:3
-
数组乱序
基本思路
1.产生一个数组长度以内的随机数作为元素下标要与最后一个元素进行交换
2.数组长度依次减少1,前一轮交换过的最后一个元素不再参与后一轮交换
比如:[1,2,3,4,5],我先产生一个 (数组长度-1)5-1=4 以内的随机数(0,1,2,3中任意一个)
假如我第一次产生的随机数为2,那么我就交换 下标2位置元素 与最后一位元素,交换后为:[1,2,5,4,3],然后进行第二轮,不管最后一位交换过的元素,看从第一个开始到倒数第二位元素间所有元素,我现在要产生 4-1=3 以内的随机数(0,1,2中任意一个)
假如我第二次产生的随机数为1,那么我就交换 下标1位置元素 与倒数第二位元素,交换后为:[1,2,5,4,3] <==> [1,4,5,2,3],以此类推,重复此操作
代码实现
package 数组常见算法总结;
import java.util.Arrays;
public class LuanXu {
public static void main(String[] args) {
int[] ns = { 1, 2, 3, 4, 5 };// 定义一个int类型数组
// 数组乱序
for (int i = ns.length - 1; i > 0; i--) {
// (int)(Math.random()*i)产生一个i以内的随机整数
int target = (int) (Math.random() * i);
// 交换随机下标位置元素与每轮尾下表
ns[i] = ns[i] ^ ns[target];
ns[target] = ns[i] ^ ns[target];
ns[i] = ns[i] ^ ns[target];
}
System.out.println("ns乱序后:" + Arrays.toString(ns));
}
}
运行结果
ns乱序后:[2, 4, 1, 5, 3]
-
数组旋转
基本思路
-
向右旋转
数组最后一个元素与前一个元素进行交换,交换交换交换,一直从末尾元素位置交换到头元素位置停止,旋转位数取决于交换次数,比如 1,2,3,4,5
第一个for循环控制旋转位数
向右旋转一位 | 1,2,3,4,5 1,2,3,5,4 1,2,5,3,4 1,5,2,3,4 5,1,2,3,4 |
向右旋转两位 [在“向右旋转一位“ 基础上接着进行一次] | 5,1,2,3,4 5,1,2,4,3 5,1,4,2,3 5,4,1,2,3 4,5,1,2,3 |
-
向左旋转
数组第一个元素与后一个元素进行交换,交换交换交换,一直从头元素位置交换到尾元素位置停止,旋转位数取决于交换次数,比如 [1,2,3,4,5]
第一个for循环控制旋转位数
向左旋转一位 | 1,2,3,4,5 2,1,3,4,5 2,3,1,4,5 2,3,4,1,5 2,3,4,5,1 |
向左旋转两位 [在“向左旋转一位“ 基础上接着进行一次] | 2,3,4,5,1 3,2,4,5,1 3,4,2,5,1 3,4,5,2,1 3,4,5,1,2 |
代码实现
package 数组常见算法总结;
import java.util.Arrays;
public class XuabZhuan {
public static void main(String[] args) {
// 定义一个int类型数组ns1
int[] ns1 = { 1, 2, 3, 4, 5 };
System.out.println("ns1: " + Arrays.toString(ns1));
// 向右旋转三位
for (int k = 1; k <= 3; k++) {// 控制旋转位数为3
for (int i = ns1.length - 1; i > 0; i--) {
// 三次异或进行交换
ns1[i] = ns1[i - 1] ^ ns1[i];
ns1[i - 1] = ns1[i - 1] ^ ns1[i];
ns1[i] = ns1[i - 1] ^ ns1[i];
}
}
System.out.println("ns1向右旋转三次结果为:" + Arrays.toString(ns1));
//=======================================================================
// 定义一个int类型数组ns2
int[] ns2 = { 1, 2, 3, 4, 5 };
System.out.println("ns2: " + Arrays.toString(ns2));
// 向左旋转三位
for (int k = 1; k <= 3; k++) {// 控制旋转位数为3
for (int i = 0; i < ns2.length - 1; i++) {
// 三次异或进行交换
ns2[i] = ns2[i] ^ ns2[i + 1];
ns2[i + 1] = ns2[i] ^ ns2[i + 1];
ns2[i] = ns2[i] ^ ns2[i + 1];
}
}
System.out.println("ns2向左旋转三次结果为:" + Arrays.toString(ns2));
}
}
运行结果
ns1: [1, 2, 3, 4, 5]
ns1向右旋转三次结果为:[3, 4, 5, 1, 2]
ns2: [1, 2, 3, 4, 5]
ns2向左旋转三次结果为:[4, 5, 1, 2, 3]