一.数组的概念
数组是用于存储一组同类型数据的数据结构,在内存中占用一段连续的空间。
二.数组定义和初始化
1.定义
数据类型 [] 变量名 ;
eg. int [] arr;
含义:定义了一个int类型的数组,变量名为arr
数据类型 变量名[];
eg. int arr[];
含义:定义了一个int类型的变量,变量为arr数组
2.初始化
静态初始化
数据类型 [] 变量名 = new 数据类型[]{数据1,数据2....};
eg. int [] arr = new int [] {1,2,3,4};
简化格式
数据类型 [] 变量名 = {数据1,数据2...};
eg. int [] arr = {1,2,3,4} ;
动态初始化
只声明数组的长度,不赋值。
格式:数据类型 [] 变量名 = new 数据类型[数组长度];
eg. int [] arr = new int [3];
注意:动态初始化时,只声明了数组的长度,但系统会给数组分配默认值,整数型为0,浮点数为0.0,字符型默认为空字符,布尔类型为false,引用类型为null
三、数组元素访问
public class ArrayTest {
public static void main(String[] args) {
int [] arr = {1,2,3,4};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
}
}
运行结果如下:
由上图得,通过数组名[索引] 可以访问数组中得元素; 其中索引指的是数组中数据的编号方式,从0开始。
四、内存分配
先简要得介绍一下java中的栈和堆,java的运行时内存可分为堆内存,栈内存,方法区和本地方法栈,栈中保存的是局部变量;堆中保存的是一些动态产生的数据,比如new出来的对象
先看一段代码
public static void main(String [] args){
// 1
int [] arr = {2,1,4};
// 2
arr [0] = 1;
// 3
int []arr1 = arr;
// 4
arr = null;
// 5
arr1[2] = 7;
}
执行1 时
执行2时
执行3时
执行4时
执行 5时
五、可能出现的异常
1.数组越界(ArrayIndexOutOfBoundsException)
访问了不在数组索引范围内(o~length-1)的元素
2.空指针异常
访问的数组不再指向堆内存中的数据
六、数组练习
1.遍历
for循环遍历
public class ArrayTest {
public static void main(String[] args) {
int [] arr = {1,2,3,4};
PrintArr(arr);
}
public static void PrintArr(int [] arr){
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i];)
}
}
}
for each遍历
public class ArrayTest { public static void main(String[] args) { int [] arr = {1,2,3,4}; PrintArr(arr); } public static void PrintArr(int [] arr){ for (int i : arr) { System.out.println(i); } } }
2.找最值
public static int GetMax(int [] arr) throws NullPointException{
if (arr!=null ){
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]){
max = arr[i];
}
}
return max;
}
else
throw new NullPonintException;
3.插入元素
前提条件:数组有足够的空间容纳插入元素
public static void insert(int[] arr, int num, int index, int count) {
/*
num:插入的值
index:插入下标
count:当前数组数据个数
*/
int temp;
// 预计插入位置不在数组索引范围内
if (index >= arr.length){
System.out.println("***");
return;
}
// 在没有元素的位置插入
if(index > count)
arr[index] = num;
else{
// 在有元素的序列中插入,从插入位置开始,整体后移
for (int i = count; i > index; i--) {
arr[i] = arr[i - 1];
}
arr[index] = num;
}
}
4.删除
public static void del(int []arr, int num){
for (int i = 0; i <arr.length; i++) {
if (arr[i] == num){
for (int j=i;j<arr.length-1;j++){
arr[j] = arr[j+1];
}
}
}
}
5.修改
已知下标的情况,直接赋值即可。
如果是有序序列,可通过二分查找找出元素的下标,再进行修改
public static void modfiy(int[] arr,int srcNum, int decNum){
for (int i = 0; i < arr.length; i++) {
if (arr[i] == srcNum){
arr[i] = srcNum;
}
}
}
6.二分查找
前提:数组是有序的,要查找的元素只有一个
执行的操作:(1)在有序序列中,开始位置定义为左节点,结束位置右节点,并计算出中间节点(2)判断中间节点对应值和待查找key值得关系,相等就返回中间节点并结束查找,大于将右节点更新为中间节点-1,小于将左节点更新为中间节点+1。(3)重复上面两步,直到左节点大于右节点。
图解:
key(查找元素):7
arr(查找数组) = {1,3,5,7,9,11,14,22,29};
代码实现
public static int binarySearch(int []arr, int key){
/*
* @param arr 待查找数组
* @param key 查找数据
* @param return index/-1 返回-1表示未找到
* */
int index = -1;
int left = 0;
int right = arr.length-1;
int mid;
// 观察第四次,不难看出 [left,right]区间依然是有效的,故left<=right
while (left<=right){
mid = left+((right-left)>>1);
//求中间值使用 mid = left+((right-left)>>1);而不用·(mid = left+right)的原因:
//1.内存溢出问题
// eg. 2的31
//2. 负数
if (key == arr[mid])
return mid;
else if (key> arr[mid])
left = mid+1;
else
right = mid-1;
}
return -1;
}
}
7.排序
冒泡排序
public static void bubble(int []arr){
/*
* @param:arr 待排序数组
* @ return
*
*/
int temp;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length-1-i; j++){
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
选择排序
public static void selectSort(int []arr){
int minIndex = 0;
int temp;
// 找出最小值放到一旁,在剩余数据中重复这一操作
for (int i = 0; i < arr.length-1; i++) {
minIndex = i;
for (int j = i ; j < arr.length; j++ ){
// 找出本轮最小值下标
minIndex = arr[minIndex] < arr[j]?minIndex : j;
}
// 将当前arr[i]与本轮最小值交换
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
插入排序
public static void insertSort(int []arr){
/*
* @param:arr
* @ return:
*/
// 假定我们手中的牌是3 2 9 7 5
// 从3开始假定其有序,2的时候,发现2<3,就和3交换 2 3 9 7 5
// 9的时候,我们发现它大于前面的牌,不动
//...
// 2 3 7 9 5 ,5比前一个数9小,交换得 2 3 7 5 9,5依然小于 7 ,再次交换,发现5>3,停止交换
int temp;
for (int i = 0; i <arr.length-1 ; i++) {
for (int j = i+1; j > 0 && arr[j] < arr[j-1]; j--) {
// 和前一个元素进行交换
ArrayUtils.swap(arr,j,j-1);
}
}
}
快速插入排序
public static void quickSort(int []arr, int left, int right){
/*
快排规则
找出一个数作为数轴,双指针向数轴靠拢,大于放右边,小于放左边
排一次,然后对左边右边分别递归执行上述步骤,直到子序列中的元素较少,使用插入排序
如果一直使用快速排序,结束条件为枢轴左侧或右侧只有一个数据
* @param:
* @ return:
*/
// 数组为空或只有一个元素,不做处理
if (arr == null || arr.length == 1 ){
return;
}
// 数组元素小于10,使用插入排序
if (right - left < 10)
InsertSort.insertSort(arr, left, right);
// 进行快排
// 找出中轴位置,并进行排序
else{
int centerAxis = firstSort(arr, left, right);
// int centerAxis = firstSort1(arr, left, right);
// 结束第一次排序,分别对两个子序列进行排序
quickSort(arr, left,centerAxis-1);
quickSort(arr, centerAxis+1,right);}
}
public static int firstSort(int [] arr, int left, int right){
// 左右指针法实现第一次排序
// 实现思路,left 往右找,直到找到一个大于key的值,停下
// right往左找,找到一个小于key的值,停下
// right 和 left交换
// 直到 right<= left
// 结束第一次排序
int key = arr[right--];
while(left < right){
while(arr[left]<=key && right> left)
left++;
while (arr[right]>=key && right > left )
right--;
// 分别找到了左边大于key,右边小于key的值,交换
ArrayUtils.swap(arr,left,right);
}
ArrayUtils.swap(key, left);
return left;
}
// 挖坑进行第一次排序找出中轴
public static int firstSort1(int []arr, int left, int right ){
int key = arr[right];
// 实现思路,取出最右边值为中枢,从左开始找,找到>key的值放到,right所在处,接着停下
// right开始找,找到<key的,放到left处
while (left < right){
while(arr[left] <= key && left < right )
left ++;
arr[right] = arr[left];
while (arr[right] >= key && left < right)
right --;
arr[left] = arr[right];
}
arr[right] = key;
return right;
}
}