一、一维数组的排序
1. 冒泡排序
冒泡排序是最常用的排序算法,算法重复的走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把它们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。
这个算法名字的由来是因为越大的元素会经由交换慢慢“浮”到数列顶端(升序排列)。
- 代码实现:
public static void main(String[] args) {
int[] array = {1,5,9,3,7,4}; //定义数组array验证冒泡排序;
bubbleSort(array);
System.out.println(Arrays.toString(array));
}
public static void bubbleSort(int[] array) {
int temp = 0;
for (int i = 0;i < array.length-1;i++) { //i是比较的趟数;
for (int j = 0;j <array.length-1-i;j++) {
if (array[j] > array[j+1]) {
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
swap = true;
}
}
}
}
- 运行结果:
-
若文件的初始状态是乱序的,需要进行n-1趟排序,每趟排序要进行n-1次的比较,且每次比较都必须移动三次来达到交换记录位置,这种情况下,该算法的时间复杂度为O(n^2);
-
若文件的初始状态是正序的,一趟扫描即可完成排序,所需的关键字的比较次数和记录移动次数均达到最小值,冒泡排序最好的情况下时间复杂度为O(n);
-
优化后的算法:
public static void bubbleSort(int[] array) {
int temp = 0;
boolean swap = false;
for (int i = 0;i < array.length-1;i++) { //i是比较的趟数;
for (int j = 0;j <array.length-1-i;j++) {
if (array[j] > array[j+1]) {
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
swap = true;
}
}
if (!swap) {
break;
}
}
}
- 算法稳定性:
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
2. 直接插入排序
直接插入排序的做法是:
- 每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
- 第一趟比较前两个数,然后把第二个数按大小插入到有序表中;
- 第二趟把第三个数据与前两个数从后向前扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
-
基本思想
每一趟将一个待排序的记录,按其关键字的大小插入到已经排好序的一组记录的适当位置上,直到所有待排序记录全部插入为止。 -
代码实现:
public static void main(String[] args) {
int[] array = {1,5,9,3,7,4}; //定义数组array验证直接插入排序;
insertSort(array);
System.out.println(Arrays.toString(array));
}
public static void insertSort(int[] array) {
int temp = 0;
int j = 0;
for (int i = 1;i < array.length;i++) {
temp = array[i]; //temp在进入查找循环之前,保存array[i]的副本;
for (j = i-1;j >= 0;j--) {
if (array[j] > temp) {
array[j+1] = array[j];
} else {
break;
}
}
array[j+1] = temp;
}
}
- 运行结果:
- 直接插入排序的时间复杂度:O(n^2);
- 算法稳定性:插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。比较是从有序序列的末尾开 始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相 等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
3. 选择排序
选择排序是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量temp来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较如果后面的元素比他要小则用变量temp记住它在数组中的位置(下标),等到循环结束的时候,应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。
- 代码实现:
public static void main(String[] args) {
int[] array = {1,5,9,3,7,4}; //定义数组array验证直接插入排序;
selectSort(array);
System.out.println("选择排序: ");
System.out.println(Arrays.toString(array));
}
public static void selectSort(int[] array) {
int temp;
for (int i = 0;i < array.length-1;i++) {
for (int j = i+1;j < array.length;j++) {
if (array[i] > array[j]) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
- 运行结果:
- 选择排序的时间复杂度:O(n^2);
- 算法稳定性:选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个 元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么 交换后稳定性就被破坏了。所以选择排序不是一个稳定的排序算法。
二、 二维数组
- 多维数组可以看成以数组为元素的数组,可以有二维,三维,甚至更多维数。
- Java支持两种类型的多维数组:
1)等长数组:也称矩形数组,在二维矩形数组中,每一行都有相同的列数;
2)交错数组:即所谓的正交数组,变长数组,锯齿形数组。在二维矩形数组中,每一行可以有不同的列数;
- 注意:交错数组比等长数组更灵活,但交错数组的创建和初始化更困难一点
- 二维数组的声明和初始化:
//Java中多维数组的声明和初始化应按照从低维到高维的顺序进行
类型名[][] 数组变量名 = new int[大小][大小]; //声明并创建一个二维数组;
类型名[][] 数组变量名 = {初始值设定项}; //声明并初始化一个数组;
类型名[][] 数组变量名 = new 类型[][]{初始值设定项}; //声明、创建并初始化一个数组;
类型名[][] 数组变量名;
数组变量名 = new 类型[大小][大小]; //先声明一个数组,然后使用new创建数组并赋值给数组;
类型名[][] 数组变量名;
数组变量名 = new 类型[][]{初始值设定项}; //先声明数组,然后创建数组并初始化、赋值给数组;
类型名[][]数组变量名 = new 类型[大小][大小];
数组变量名[下标] = 初始值; //声明并初始化数组,然后利用赋值语句初始化该实例;
- 二维数组的内存分配图:
- 二维数组的基本访问操作
二维数组可以理解为数组的数组:
- 通过数组的length属性可以获取数组的长度,其基本形式:
数组变量名.length; //返回“数组变量名”的元素个数;
数组变量名[下标].length; //返回“数组变量名[下标]”(数组)的元素个数;
数组变量名[下标][下标].length; //返回“数组变量名[下标][下标]"(数组)的元素个数;
- 打印数组元素:
(1)for循环;
public static void main(String[] args) {
System.out.println("用for循环打印数组元素:");
int[][] array;
array = new int[][]{{1,2,3},{4,5,6}};
for (int i = 0;i < array.length;i++) {
for (int j = 0;j < array[i].length;j++) {
System.out.print (array[i][j] + " ");
}
}
}
运行结果:
(2)foreach循环
- foreach-foreach;
public static void main(String[] args) {
System.out.println("用foreach循环打印数组元素:");
int[][] array;
array = new int[][]{{1,2,3},{4,5,6}};
for (int[] m : array) {
for (int n : m) {
System.out.print(n + " ");
}
}
}
运行结果:
- foreach-Arrays.toString;
public static void main(String[] args) {
System.out.println("用foreach循环打印数组元素:");
int[][] array;
array = new int[][]{{1,2,3},{4,5,6}};
for (int[] m : array) {
System.out.println(Arrays.toString(m));
}
}
运行结果:
(3)Arrays.deeptoString();
public static void main(String[] args) {
System.out.println("调用Arrays.deeptoString()打印数组元素:");
int[][] array;
array = new int[][]{{1,2,3},{4,5,6}};
System.out.println(Arrays.deepToString(array));
}
运行结果:
- 二维数组的拷贝方式:
- for循环;
- clone;
- System.arraycopy();
- Arrays.copyOf();
用法跟一维数组的拷贝相同
三、打印三阶魔方阵
程序代码:
public static void main(String[] args) {
int[][] array = new int[3][3];
//int Row = array.length;
int x = 0; //x,y为数组下标;
int y = 1;
array[x][y] = 1;
for (int i = 2;i <= 9;i++) {
x = (x-1+3) % 3;
y = (y+1) % 3;
if (array[x][y] != 0) {
x = (x+1+1) % 3;
y = (y-1+3) % 3;
}
array[x][y] = i;
}
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
}
运行结果:
四、打印奇数阶魔方阵
程序代码:
import java.util.Scanner;
public class test02 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入魔方阵的阶数: "); //输入一个大与等于3奇数;
int Row = scan.nextInt();
System.out.println("=====================");
int[][] array = new int[Row][Row];
matrix(array,Row);
}
public static void matrix(int[][] array,int Row) {
int x = 0; //x,y为数组下标;
int y = Row/2;
array[x][y] = 1;
for (int i = 2;i <= Row * Row;i++) { // 将[2,Row^2],Row^2-1个数字放入数组array中;
x = (x-1+Row) % Row; //若x = (x-1) % Row,当x = 0时,数组越界;x = (x-1+Row) % Row使x始终大于0;
y = (y+1) % Row;
if (array[x][y] != 0) { //若当前数字的上一行下一列的元素不为0,则将下一个数字放在当下数字的下一行;
x = (x+1+1) % Row; //因为在本次循环开始时已经改变了x,y的值,所以当进入if语句时应将x置为上次循环结束时的值,之后再做改变;
y = (y-1+Row) % Row; //
}
array[x][y] = i;
}
//打印矩阵;
for (int i = 0;i < Row;i++) {
for (int j = 0;j < Row;j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
}
}
运行结果: