文章目录
一、数组
数组: 是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
- 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。
- 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是 这块连续空间的首地址。
- 数组的长度一旦确定,就不能修改。
- 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
- 分类:按维度分为一维、二维等;按照元素的数据类型分为基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)。
二、数组的分类
1.一维数组
①如何对一维数组进行声明和初始化?
–首先指明数组元素类型,由于数组本身是引用数据类型,所以需要new。如
int[] ids;//声明为int型数组
ids = new int[]{21,22,23};//初始化
以上为静态初始化过程(数组元素为基本数据类型,数组初始化和数组元素的赋值操作同时进行);
对于动态初始化(数组初始化和数组元素的赋值操作分开进行),则写法为
String[] names = new String[5];
②如何获取数组长度及遍历数组?
String[] names = new String[3];
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
System.out.println(names.length); //打印出该数组长度
for(int i = 0;i<names.length;i++) //遍历输出
{
System.out.println(names[i]);
}
③对数组的内存解析
内存的简化: 简单分为栈和堆,栈中存的局部变量(放方法中的变量均为局部变量),堆中存的new出来的结构,如图(参考尚硅谷学习)。
理解分析: 右上角为示例部分代码,以第一行为例分析,arr在main方法中,是局部变量,存入栈中;右侧new出了长度为3的数组,存入堆中;三个连续的单元有首地址值,假设为0x34ab(十六进制),会将其赋给栈空间中的arr,则其会通过此地址值找到堆中的数组,从而联系起来;然后进行赋值为1 2 3(因为默认为0 0 0)。
2.多维数组
分析二维数组:可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。
①声明与初始化
静态初始化:
int[][] arr1 = new int[][]{{2,3,4},{2,5},{1,2,3,4}};
动态初始化:
int[][] arr2 = new int[3][2];
②长度与遍历
//获取数组长度
int[][] arr3 = new int[][]{{2,3,4},{2,5},{1,2,4}};
System.out.println(arr3[].length);//3
System.out.println(arr3[0].length); //3
System.out.println(arr3[1].length); //2
for(int i = 0;i<arr3.length;i++) //遍历输出
{
for(int j = 0;j<arr3[i].length;j++) {
System.out.print(arr3[i][j]+" ");
}
}
三、数组的使用
1.数组元素的赋值
例: 创建一个长度为6的int型数组,要求随机生成数组元素的值,且都在1~30之间。同时,要求元素的值各不相同。
补充: 生成随机数的方法是通过java.Math包的random方法得到。
公式是:(数据类型)(最小值+Math.random()*(最大值-最小值+1))
如1~30之间的写法是 (int)( 1 + (Math.random() * 30))
方法1:
public class Array {
public static void main(String[] args) {
int[] arr = new int[6];
for (int i = 0; i < arr.length; i++) {// [0,1) [0,30) [1,31)
arr[i] = (int)( 1 + (Math.random() * 30));
boolean flag = false;//标志位
while (true) {
for (int j = 0; j < i; j++) {
if (arr[i] == arr[j]) {
flag = true;
break;
}
}
if (flag) {
arr[i] = (int)( 1 + (Math.random() * 30));
flag = false;
continue;
}
break;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
方法2:
public class Array {
public static void main(String[] args) {
int[] arr = new int[6];
for (int i = 0; i < arr.length; i++) {// [0,1) [0,30) [1,31)
arr[i] = (int)( 1 + (Math.random() * 30));
for (int j = 0; j < i; j++) {
if (arr[i] == arr[j]) {
i--;
break;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
2.求最大和最小值
在main中写法:
int[] arr;
arr=new int[]{1,2,3,4,5,6};
int maxValue = 0;
for(int i = 0; i < arr.length;i++) {
if(maxValue < arr[i]) {
maxValue = arr[i];
}
}
int minValue =arr[0];//初始设最小为数组第一个元素
for(int i = 1; i < arr.length;i++) {
if(minValue > arr[i]) {
minValue = arr[i];
}
}
System.out.println("最大为:"+maxValue +"最小为:"+minValue);
}
3.数组的查找(线性、二分法查找)
3.1 线性查找
int[] arr;
arr=new int[]{3,22,32,44,13,64};
int cha=64;
for(int i = 0;i <arr.length;i++)
{
if(cha==arr[i]) {//字符串用equals(arr[i])方法
System.out.println("找到了所查找元素,位置为:"+i);
}
}
3.2 二分法查找
前提:所要查找的数组必须有序
int[] arr= new int[]{3,4,6,8,13,24};
int cha=13;
int head = 0;//初始首索引
int end = arr.length-1;//初始末索引
boolean isFlag=true;
while( head <= end)
{
int middle = (head + end)/2;
if(cha == arr[middle])
{
System.out.println("找到了所查找元素,位置为:"+middle);
isFlag=false;
break;
}
else if(cha < arr[middle])
{
end = middle-1;
}
else
{
head = middle+1;
}
}
if(isFlag) {
System.out.println("没有找到!");
}
4 冒泡排序与快速排序
4.1 冒泡排序(Bubble Sort)
概念:
通过相邻的两个元素两两比较,根据大小来交换位置,最值元素就像气泡一样从左侧向右侧移动。
步骤:
- 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步
做完后,最后的元素会是最大的数。 - 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要
比较为止。
举例说明:
代码示例:
package com.qihang;
public class BubbleSort {
public static void main(String[] args) {
int[] arr=new int[]{43,22,14,35,78,42};
//冒泡排序
// 外层--表几大轮
for(int i = 0; i< arr.length-1;i++)
{
for(int j = 0;j<arr.length-1-i;j++)//i=0,比较5次;i=1;比较4次……
{
if(arr[j]>arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
// 输出数组
for(int i = 0; i < arr.length;i++) {
System.out.print(arr[i]+" ");
}
}
}
输出:
4.2 快速排序(Quick Sort)
概念:
快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一,是迄今为止所有内排序算法中速度最快的一种。冒泡排序的升级版,交换排序的一种。快速排序的时间复杂度为O(nlog(n))。
排序思想:
- 从数列中挑出一个元素,称为"基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准
值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,
该基准就处于数列的中间位置。这个称为分区(partition)操作。 - 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数
列排序。 - 递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好
了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代
(iteration)中,它至少会把一个元素摆到它最后的位置去
关于快速排序主要理解思想、做法。
4.3 各种排序的比较
- 从平均时间而言: 快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。
- 从算法简单性看: 由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。
- 从稳定性看: 直接插入排序、冒泡排序和归并排序是稳定的;而直接选择排序、快速排序、Shell(希尔)排序和堆排序是不稳定排序。
排序算法的选择
(1)若n较小(如n≤50),可采用直接插入或直接选择排序。 当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插入,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插入、冒泡或随机的快速排
序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或
归并排序。
四、Arrays工具类的使用
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组( 比如排序(底层代码用的快排写法)和搜索 )的各种方法。
- 主要结合API文档使用。( 可参考本篇文章获取API文档 )
常见的有
代码示例:
package com.qihang;
import java.util.Arrays;//注意导包
public class Array {
public static void main(String[] args) {
// boolean equals(int[] a,int[] b) 判断两个数组是否相等。
int[] arr1=new int[]{1,2,3,4};
int[] arr2=new int[]{1,2,4,3};
boolean isEquals =Arrays.equals(arr1,arr2);
System.out.println(isEquals);//输出false
// String toString(int[] a) 输出数组信息
System.out.println(Arrays.toString(arr1));//输出[1, 2, 3, 4]
}
}