黑马毕向东Java课程笔记(day03—第三部分+day04):数组(排序算法)+java内存分配

  我们会介绍数组的定义、内存分配及特点、操作常见问题、常见操作以及数组中的数组几个部分。

1、数组的定义
在这里插入图片描述
  数组定义:
格式1

元素类型[] 数组名 = new 元素类型[]{元素}//动态初始化

元素类型[] 数组名 = new 元素类型[元素个数或者数组程度长度] 
或元素类型[] 数组名 = {元素}//这两种定义方法是静态初始化,是一样的

注意:
  数组是一种单独的数据类型(引用数据类型)

2、数组的内存结构
  Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,有对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。java在运行的时候将内存划分为5片区域,方法区、堆内存(线程共享)、本地方法区、寄存器(程序计数器)、虚拟机栈(线程隔离)
具体内存的分配可以参考下面这篇文章:
java内存区域划分
  关于内存还可以参考(就业班-day05-pdf相关解析以及就业班-day05-07、08(重要)、09、10视频解析 )
  栈内存:用于存储局部变量,当数据使用完,所占空间会自动释放。
局部变量:定义在方法中的变量;而定义在类里面的变量则是全局变量
  堆内存:数组和对象,通过new建立的实例都存放在堆内存中。每一个实体都有内存地址值,实体中的变量都有默认初始化值。实体不再使用,会在不确定的时间内被垃圾回收器回收。

在这里插入图片描述
  首先,我们int[] arr,那么在栈内存中就会开辟一个空间存放数组变量arr。而new出来的实体,会存放在堆里面,实体包括数组和对象。也就是说,当我们new int[4]的时候,系统会在堆内存里面开辟4块空间来存放实体,且每一个空间都有一个编号与值(有指定就取指定值,如果没有指定就会默认初始化值int0,double0.0,boolean false)。
  堆与栈的联系:首先,系统在堆中开辟一个内存空间存放实体,假设该内存空间的起始地址为0x0012,我们将这个地址值赋予栈内存中的x,用该地址来标识数组位置,这样x就指向数组,或者说x引用了数组。栈中x没有存放堆中数组的实体,而只是存放地址
  我们定义int[] x = new int[3],如果设置x=null(空),这时x不指向数组堆中的内存空间,堆内存的空间没有任何引用来使用它。java会在不定时的时间内启动垃圾清除机制,将垃圾清除。
  c++中的垃圾需要程序员手动清除,java堆中则有垃圾自动回收机制,栈中的垃圾在不使用的时候会自动释放。
  要注意int[] arr与 new int[3]两部分的不同内存操作的涵义。

3、数组操作常见问题
在这里插入图片描述
4、数组常见操作
A、遍历数组
  首先举一个使用for循环遍历二元数组的例子

public static void main(String[] args) {
		int[][] array = new int[][] {{1,2,3,4},{2,6,8},{8,0,1,5,6}};
		for(int x=0; x<array.length ;x++) {//注意这里取数组长度的格式
			for(int y=0; y<array[x].length ;y++) {//注意这里取内层数组长度的格式
				System.out.print(array[x][y]+" ");
			}
			System.out.println();
		}

  接下来我们试着用foreach的形式遍历

public static void main(String[] args) {
		int[][] array = new int[][] {{1,2,3,4},{2,6,8},{8,0,1,5,6}};
		
		int i = 0;//设置i为外层循环的遍历计数器
		for(int innerArray[]: array) {//由于数组为二元数组,外部循环变量应设置为一维数组,使用一维数组来遍历,这样内部循环才可以继续遍历
			i++;//外层遍历一次,i自加1
			int j = 0;//设置i为内层循环的遍历计数器
			for(int x:innerArray) {//用x遍历内部数组
				/*
				 * 每遍历一个内层数组j自动加一,注意j必须在第一个for循环内设置,
				 * 外循环每循环一次就会自动把j置零,这样才可以达到找到最后一个元素的效果,否则j会一直增加*/
				j++;
				if(i==array.length && j==innerArray.length) {
					System.out.print(x);
				}else {
					System.out.print(x+"、");
				}
			}
		}
	}

  需要注意,上面的i,j只是用来控制输出,如果“、”用“ ”(空格)代替,不需要设置x,y。

123426880156

  试着打印一元数组

public static void main(String[] args) {
		int[] array = new int[] {2,4,56,78,12};
		
		for(int x=0; x<array.length ;x++) {
			if(x==array.length) {//这里一元的只需要用x即可,而上面二元是foreach则需要用i,j
				System.out.print(array[x]);
			}else {
				System.out.print(array[x]+",");
			}
		}
	}

  如果我们直接打印数组,

int[] array = new int[] {2,4,56,78,12};
System.out.println(array);

结果是,我们打印的是数组实体的引用

[I@7852e922 //[代表数组,I指数组中的元素类型,7852e922是数组的内存存放地址(十六进制表示),是由哈希算法计算得出的哈希值

B、获取数组最值

package lkj;
/*
给定一个数组,获取其最值
*/
public class Main {
	public static void main(String[] args) {
		int[] array = new int[] {2,4,5,18,12,1,5,-1,56,-4};
		
		System.out.println("数组元素最大值为:"+getMax(array));
		System.out.println("数组元素最小值为:"+getMin(array));
		
	}
	
	public static int getMax(int[] array) {
		int max = array[0];//设定一个参数来存放最大值
		
		for(int x=1; x<array.length ;x++){
			if(array[x] > max) {
				max = array[x];
			}
		}
		return max;
	}
	
	public static int getMin(int[] array) {
		int min = array[0];//设定一个参数来存放最小值
		
		for(int x=1; x<array.length ;x++) {
			if(array[x] < min) {
			min = array[x];
			}
		}
		return min;
	}
}

C、数组排序
  常见的排序算法有冒泡排序、直接选择排序和反转排序。
(1)冒泡排序
  思想:就是按一定的规律把相邻2个数对比,并把当次最大的数排到最后(内循环从头到尾两两排序)或者把当次最小的数排到最前面(内循环从尾到头两两排序)。外循环用于控制排序轮数,一般等于数组的长度减一;内循环用于对比数组中临近元素的,对比轮数随排序轮数的增加而减少。

内循环从头到尾两两排序


public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {9,1,2,3,8,7,4,6,10};

		SortTest obj = new SortTest();//创建本类的对象
		obj.bubbleSortPositive(array);
		
	}

	public static void bubbleSortPositive(int[] array) {//正冒泡排序,既内循环从头到尾
		int num = 0;//定义num来计算比较次数
		for(int i=1; i<array.length ;i++) {
			//内循环的次数与外循环的轮数相关,因此要将他们联系起来,这里j必须从0开始,否则可能会数组越界
			//每一轮的内循环都到array.length-i,每一轮都将此轮最大的数排到最后,因此从下标是array.length-i到array.length的数不需要再排
			for(int j=0; j<array.length-i ;j++) {
				num++;//num计算的是比较的次数,不是换数的次数,因此我们将其设置在外面
				if(array[j]>array[j+1]) {
					//或者利用下面的方法交换两个数也是一样的
					array[j] = array[j]^array[j+1];
					array[j+1] = array[j]^array[j+1];
					array[j] = array[j]^array[j+1];
				}
			}
		}
		System.out.println("比较的次数为:"+num);
		showArray(array);		
	}
	
	public static void showArray(int[] array) {
		for(int i=0; i<array.length ;i++) {
			if(i == array.length-1) {
				System.out.print(array[i]);
			}else {
				System.out.print(array[i]+">");
			}
		}
	}
}

结果:

比较的次数为:36
1>2>3>4>6>7>8>9>10
//一共比较(8+1)*8/2=36次,符合计算规则

冒泡排序优化

public static void bubbleSortPositive(int[] array) {//正冒泡排序,既内循环从头到尾
		int num = 0;//定义num来计算比较次数
		boolean flag = true;//定义一个布尔型参数来判断是否需要继续执行排序
		
		for(int i=1; i<array.length && flag==true;i++) {//当flag=true的时候才继续执行下一轮的排序
			flag = false;
			//内循环的次数与外循环的轮数相关,因此要将他们联系起来,这里j必须从0开始,否则可能会数组越界
			//每一轮的内循环都到array.length-i,每一轮都将此轮最大的数排到最后,因此从下标是array.length-i到array.length的数不需要再排
			for(int j=0; j<array.length-i ;j++) {
				num++;//num计算的是比较的次数,不是换数的次数,因此我们将其设置在外面
				if(array[j]>array[j+1]) {
					//或者利用下面的方法交换两个数也是一样的
					array[j] = array[j]^array[j+1];
					array[j+1] = array[j]^array[j+1];
					array[j] = array[j]^array[j+1];
					/*
					 * 对于某一轮的对比,如果存在换数行为,说明还可能存在不按顺序排列的数,我们会将flag置true,并继续执行下一轮,
					 * 如果不存在换数行为,说明换数已经结束,不需要执行下一轮的排序,此时flag为假,那么说明数组已经顺序排列,不需要再对比
					 * 这一方法主要判断的是不存在换数行为排序已经完成
					 */
					flag = true;
				}
			}
		}
		System.out.println("比较的次数为:"+num);
		showArray(array);		
	}

结果为:

比较的次数为:26
1>2>3>4>6>7>8>9>10

内循环从尾到头两两排序


public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {1,2,5,3,6,7,8,9,10};

		SortTest obj = new SortTest();//创建本类的对象
		obj.bubbleSortNegative(array);
		
	}

	public static void bubbleSortNegative(int[] array) {//正冒泡排序,既内循环从头到尾
		int num = 0;//定义num来计算比较次数
		boolean flag = true;//定义一个布尔型参数来判断是否需要继续执行排序
		
		for(int i=1; i<array.length && flag==true;i++) {//当flag=true的时候才继续执行下一轮的排序
			flag = false;
			//内循环的次数与外循环的轮数相关,因此要将他们联系起来,这里j必须从0开始,否则可能会数组越界
			//每一轮的内循环都从array.length-i开始,每一轮都将此轮最小的数排到最前面,因此从下标是0到i-1的数不需要再排
			for(int j=array.length-1; j>=i ;j--) {
				num++;//num计算的是比较的次数,不是换数的次数,因此我们将其设置在外面
				if(array[j]<array[j-1]) {//这里要特别注意正负号!
					//或者利用下面的方法交换两个数也是一样的
					array[j] = array[j]^array[j-1];
					array[j-1] = array[j]^array[j-1];
					array[j] = array[j]^array[j-1];
					/*
					 * 对于某一轮的对比,如果存在换数行为,说明还可能存在不按顺序排列的数,我们会将flag置true,并继续执行下一轮,
					 * 如果不存在换数行为,说明换数已经结束,不需要执行下一轮的排序,此时flag为假,那么说明数组已经顺序排列,不需要再对比
					 * 这一方法主要判断的是不存在换数行为排序已经完成
					 */
					flag = true;
				}
			}
		}
		System.out.println("比较的次数为:"+num);
		showArray(array);		
	}
	
	public static void showArray(int[] array) {
		for(int i=0; i<array.length ;i++) {
			if(i == array.length-1) {
				System.out.print(array[i]);
			}else {
				System.out.print(array[i]+"<");
			}
		}
	}
}

结果是:

比较的次数为:15
1<2<3<5<6<7<8<9<10
//9个数正常情况下需要36次排序,这里用15次排序就解决,说明算法有所优化

(2)直接选择排序
  直接选择排序是选择排序的一种,它的排序速度比冒泡排序要快一点。
  主要思想:从一列数中选出符合指标的某个数,并把它的位置与指定排序位置交换。比如从一列数中选择出最大的数并把它与最后的数的位置交换。(由于直接选择排序是通过比较后交换下标,找出符合条件数的下标(如最大数),等比较结束后再进行交换,所以交换次数较少,比冒泡排序要快)


public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {12,2,25,3,36,7,48,9,123};

		SortTest obj = new SortTest();//创建本类的对象
		obj.selectSort(array);
		
	}

	public static void selectSort(int[] array) {
		
		//外循环用于控制内循环找到最大数的下标之后,进行交换的次数,等于数组长度减一
		for(int i=1; i<=array.length-1; i++) {
		//index必须设置在外循环中内循环外,因为每一个外循环开始都必须从0角标开始比较
			int index = 0;//首先创建一个变量用来保存比较过程中数的下标
			//内循环每一轮需要比较到最远的位置是array[array.length-i],因为每一轮循环之后都会将当前最大的数排序到最后
			//且j从1开始,因为0的位置已经被index所占
			for(int j=1; j<=array.length-i ;j++) {
				if(array[j]>array[index]) {//相当于找出最大数的下标
					index = j;//如果j位置比index位置的数要大,j与index交换
				}
			}
			//找到当前轮最大数的下标之后,将其移动到本轮的最末端位置array.lengeh-i,既交换array[index]与array[array.lengeh-i]位置的数
//			array[index] = array[index]^array[array.length-i];
//			array[array.length-i] = array[index]^array[array.length-i];
//			array[index] = array[index]^array[array.length-i];
			int temp = array[array.length-i];
			array[array.length-i] = array[index];
			array[index] = temp;
		}
		
		showArray(array);		
	}
	
	public static void showArray(int[] array) {
		for(int i=0; i<array.length ;i++) {
			if(i == array.length-1) {
				System.out.print(array[i]);
			}else {
				System.out.print(array[i]+"<");
			}
		}
	}
}

结果:

2<3<7<9<12<25<36<48<123
异或方法
2<3<0<9<12<25<36<48<0
//异或交换数的方法格式并没有写错,为什么会出现错误?出现0的位置都正确,说明我们内部排序没有出错,而是在交换的时候出错导致其置零。有大神看出为什么麻烦在评论下或者私信我告知,谢谢!!!

普通选择排序


public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {45,12,16,58,23,56,78,4,6};

		SortTest obj = new SortTest();//创建本类的对象
		obj.selectSort(array);
		
	}

	//普通选择排序
	//其实普通选择排序类似于直接选择排序,只不过直接选择排序是通过对比,找出角标最大(小)的数,然后再进行交换
	//而普通选择排序则是一一比较后直接对换,这样便使得程序的执行时间较长
	public static void selectSort(int[] array) {
		for(int i=1; i<array.length ;i++) {//对比array.length-1轮
			for(int j=i; j<array.length ;j++) {
				if(array[i-1]>array[j]) {
					int temp = array[i-1];
					array[i-1] = array[j];
					array[j] = temp;
				}
			}
		}
		showArray(array);
	}
	
	public static void showArray(int[] array) {
		for(int i=0; i<array.length ;i++) {
			if(i == array.length-1) {
				System.out.print(array[i]);
			}else {
				System.out.print(array[i]+",");
			}
		}
	}
}

  直接选择排序毕普通选择排序的性能高,是因为它只在栈内存中进行角标的交互,等找到当前的最值之后,再在堆内存中进行实际值的交换,这样便节省了在堆内存中所占的空间。要注意,堆内存操作是比较占内存空间的!

(3)反转排序
  以相反的顺序把原有数组的内容重新排序。只需要循环数组长度的半数次,如数组的长度为7,则只需要循环3次。


public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {1,2,3,4,5,6,7};

		SortTest obj = new SortTest();//创建本类的对象
		obj.reverseSort(array);
		
	}

	public static void reverseSort(int[] array) {
		System.out.print("原数组为:");
		showArray(array);
		
		int length = array.length;//获取数组长度
		//如果length为偶数,那么交换的次数为length/2,若其为奇数,则交换次数为(length-1)/2
		//注意此处i<(length-1)/2,其实可以写作i<(length)/2,但是如果这样,当数组长度为奇数的时候,会多出一次无谓的交换,既中间的数与自己交换
		for(int i=0; i<(length-1)/2 ;i++) {
			int temp = array[i];
			array[i] = array[length-1-i];
			array[length-1-i] = temp;
		}
		System.out.println();
		System.out.print("反转排序后的数组为:");
		showArray(array);
	}
	
	public static void showArray(int[] array) {
		for(int i=0; i<array.length ;i++) {
			if(i == array.length-1) {
				System.out.print(array[i]);
			}else {
				System.out.print(array[i]+",");
			}
		}
	}
}

数组排序——位置置换功能的抽取

//对于这一部分,我们可以用一个交换函数替换
		int temp = array[i];
		array[i] = array[length-1-i];
		array[length-1-i] = temp;
		
		swap(array,i,length-1-i);
//如果不把数组也添加到形参中,swap()内数会在内存中开辟另一块区域并执行换数
//swap()中的换数与数组相关,如果不把数组传递进来,数组的数并不会随着swap()函数的交换而交换,而仅仅是交换了i与length-1-i的值
public static void swap(int[] array,int a,int b){
	int temp = array[a];
	array[a] = array[b];
	array[b] = temp;
}

//当然,上面其实有点复杂化了,也可以不考虑数组,直接交换数组内的2个数,这样就不用把数组也加入形参
	swap(array[i-1],array[j]);

	public static void swap(int a,int b){
		int temp = a;
		a = b;
		b = temp;
	}

D、数组查询
  普通查找方法

//比如我们想要查找数组内的某一个数,我们一般会遍历整个数组
public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {45,12,16,58,12,23,56,78,12,4,6};

		SortTest obj = new SortTest();//创建本类的对象
		
		int index = getIndex(array,12);
		System.out.println("index="+index);
		
		
	}

	public static int getIndex(int[] array,int key) {
		
		for(int x=0; x<array.length ;x++) {
			if(array[x] == key) {
				return x;
			}
		}
		return -1;
	}
}

  折半查找,效率较高,但是必须对数组提前进行排序

//考虑我们所查找的数在数组中可能不存在,利于折半的中间值array[mid]!=key
import java.util.*;
public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {45,16,58,23,56,78,12,4,6};
		int index = 0;
		
		//首先,如果要使用折半排序,必须先对数组进行排序
		Arrays.sort(array);
		System.out.print("排序后的数组为:");
		showArray(array);
		
		System.out.println();
		index = halfSearch(array,100);
		System.out.println("index="+index);
		
		
	}

	public static int halfSearch(int[] array,int key) {
		int min = 0;//定义min来保存折半查找的下限
		int max = array.length-1;//定义max来保存折半查找的上限
		int mid = (min+max)/2;//定义mid来保存折半查找的中间值
		
		while(array[mid] != key) {//如果中间值的数不等于查找的数
			/*
			 通过下面这个循环就可以找到满足条件的mid,如果不理解,自己画个图就清楚
			 */
			if(key>array[mid]) {
				min = mid+1;//key大于中间值下标的数值,min等于mid+1
			}else if(key<array[mid]){
				max = mid-1;//key大于中间值下标的数值,max等于mid-1
			}
			//通过画图我们知道,如果所查找的数不存在于数组中,会出现min=max,下一次就是min>max
			//在min=max的时候,如果array[mid]任然不等于key,说明数组中没有我们想要查询的数,返回-1(注意min=max的时候也必须求,只有max<min的时候才可以停止比较)
			if(max == min && array[mid] != key) {
				return -1;
			}
			//当然,也可以不判断min=max,直接判断min>max,这个时候铁定array[mid]任然不等于key,那么说明数组中没有我们想要查询的数,返回-1
			//这两种方法的区别在于下面这种方法多做了一次循环
			if(max<min){
				return -1;
			}
			mid = (min+max)/2;
		}
		return mid;//当中间值等于我们所查找数的下标的时候,返回中间值
	}
	
	public static void showArray(int[] array) {
		for(int x=0; x<array.length ;x++) {
			if(x == array.length-1) {
				System.out.print(array[x]);
			}else {
				System.out.print(array[x]+",");
			}
		}
	}
}		
//折半的另一个思路,我们前面说到,当min>max的时候,说明不存在我们要查找的数
//那么,我们将循环条件设置为min<=max,这样子一直查找,找到就返回mid,
//找不到就说明不存在我们要查找的数,跳出循环返回-1
import java.util.*;
public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {45,16,58,23,56,78,12,4,6};
		int index = 0;
		
		//首先,如果要使用折半排序,必须先对数组进行排序
		Arrays.sort(array);
		System.out.print("排序后的数组为:");
		showArray(array);
		
		System.out.println();
		index = halfSearch(array,56);
		System.out.println("index="+index);
		
		
	}

	public static int halfSearch(int[] array,int key) {
		int min = 0;//定义min来保存折半查找的下限
		int max = array.length-1;//定义max来保存折半查找的上限
		int mid = (min+max)/2;//定义mid来保存折半查找的中间值
		
		while(min<=max) {//如果min<=max,继续查找
			
			if(key>array[mid]) {
				min = mid+1;
			}else if(key<array[mid]){
				max = mid-1;
			}else {//当array[mid]=key,找到我们要查询的数
				return mid;
			}
			mid = (min+max)/2;
		}
		return -1;//当max>min,说明所查找的数不存在,返回-1
	}
	
	public static void showArray(int[] array) {
		for(int x=0; x<array.length ;x++) {
			if(x == array.length-1) {
				System.out.print(array[x]);
			}else {
				System.out.print(array[x]+",");
			}
		}
	}
}	

  总结
我们列一组数据如1,3,5,7,9,11,13,假设我们要查找10并插入,那么有:
min = 0、max = 7-1 = 6、mid = 3
发现array[mid] = array[3] = 7<10,那么:
min = min+1 = 4、max = 6、mid = 5
发现array[mid] = array[5] = 11>10,那么:
min = 4 、max = mid-1 = 4、mid = 4
发现array[mid] = array[4] =9<10,那么:
min = mid+1 = 5,max = 4、mid = 4.5
说明10应该插入下标为5的位置!

至此,我们发现一种折半下去,会出现min = max以及min>max的情况,如果要插入数,当min>max的时候:
(1)若不存在与要插入数相同的数,则min的位置就是我们要插入的位置;
(2)若存在于原数相同的数,mid的位置就是我们要插入的位置。

练习:

//练习:有一个有序的数组,想要将一个元素插入到该数组中,还要保证该数组是有序的。
import java.util.*;
public class SortTest {

	public static void main(String[] args) {
		int [] array = new int[] {45,16,58,23,23,78,12,4,6};
		int index = 0;
		
		//首先,如果要使用折半排序,必须先对数组进行排序
		Arrays.sort(array);
		System.out.print("插入前的数组为:");
		showArray(array);
		
		System.out.println();
		
		int insertLocation = halfSearch(array,23);//定义一个数来获取我们要插入的位置
		int[] newArray = insertArray(array,insertLocation,23);//获取插入的数组
		System.out.print("插入后的数组为:");
		showArray(newArray);
		
		
	}
     //该方法用于获取插入位置
	public static int getInsertLocation(int[] array,int insert) {
		int min = 0;//定义min来保存折半查找的下限
		int max = array.length-1;//定义max来保存折半查找的上限
		int mid = (min+max)/2;//定义mid来保存折半查找的中间值
		
		/*
		 *前面说我们要插入数,如果查找到,说明mid就是我们要插入的位置,且这个位置原来的数与我们要插入的数相同
		 *如果没有查找到,我们返回min,min就是我们要插入的位置 
		 */
		while(min <= max) {
			if(insert>array[mid]) {
				min = mid+1;
			}else if(insert<array[mid]){
				max = mid-1;
			}else {//当array[mid]=key
				return mid;
			}
			mid = (min+max)/2;
		}
		//当min>max的时候,表示满意找到,跳出循环
		return min;
	}
	
	//该方法的第一个参数是我们要排序的数组,第二个参数是要插入的位置,第三个参数是我们要插入的数,用于获取插入后的数组
	//对于insertLocation=min,我们直接把这个位置原来的数的下标都加一位,把我们要插入的数插入这个位置即可
	//对于insertLocation=mid,由于insertNum等于数组原来这个位置的数,同样把这个位置原来的数的下标都加一位,效果是一样的
	public static int[] insertArray(int[] array,int insertLocation,int insertNum) {
		int[] newArray = new int[array.length+1] ;//定义一个比原数组厂一个数的数组
		
		for(int x=0;x<insertLocation;x++) {//对于insertLocation之前的数,直接将Array的值赋予即可
			newArray[x] = array[x];
		}
		newArray[insertLocation] = insertNum;//将我们要插入的数插入相应的位置
		//对于insertLocation+1位置开始的数,将array数组从下标为insertLocation开始的数赋予即可
		for(int y=insertLocation+1; y<newArray.length ;y++) {
			newArray[y] = array[y-1];
		}
		
		return newArray;//结果返回一个插入的数组
	}
	
	public static void showArray(int[] array) {
		for(int x=0; x<array.length ;x++) {
			if(x == array.length-1) {
				System.out.print(array[x]);
			}else {
				System.out.print(array[x]+",");
			}
		}
	}
}
//结果是无论数组中有没有我们要插入的数,或者有几个我们要插入的数,排序都成功!	

E、数据进制转换
(1)十进制转二进制与十进制转十六进制

import java.util.*;
public class SortTest {

	public static void main(String[] args) {
		toBin(60);
		System.out.println();
		toBin_2(-6);
		System.out.println();
		toHex(60);
		System.out.println();
		toHex_2(60);
		
	}
	
	/*
	 * 十进制转二进制
	 */
	public static void toBin(int num) {
		System.out.print(num+"的二进制形式为");
		StringBuffer sb = new StringBuffer();//用StringBuffer类创建一个保存字符串的容器sb
		while(num != 0) {
			sb.append(num%2);//用append方法将获取的数保存到容器内
			num=num/2;
		}
		System.out.print(sb.reverse());
	}
	/*
	 * 查表法十进制转二进制
	 */
	public static void toBin_2(int num) {
		//定义二进制的表
		char[] chs = {'0','1'};
		//定义一个数组用来保存num的各个二进制位,int数最多有32位,因此数组长度应该为32
		char[] arr = new char[32];
		//定义一个指针用来遍历num的各位
		int pos = 0;
		
		while(num != 0) {
			int temp = num&1;//定义temp临时保存二进制位
			arr[pos++] = chs[temp];
			num = num>>>1;//查完一个二进制位后,num右移一位
		}
		System.out.print(num+"的二进制形式为:");
		for(int x=pos-1; x>=0 ;x--) {//从最后有数保存的位置pos-1开始反向遍历
			System.out.print(arr[x]);
		}
		
	}
	
	/*
	 * 十进制转十六进制
	 */ 
	public static void toHex(int num) {
		StringBuffer sb = new StringBuffer();//用StringBuffer类创建一个保存字符串的容器sb
		while(num != 0) {//n1=0的时候说明不需要 
			int temp = num & 15;
			if(temp>9)
				sb.append((char)(temp-10+'A'));
			else
				sb.append(temp);
			
			num = num>>>4;
		}
		System.out.print("十六进制形式为:0x"+sb.reverse());
	}
	
	/*
	 * 查表法十进制转十六进制
	 * 查装法:将所有的元素临时存储起来。建立对应关系。
	 * 每一次&15后的值作为索引去查建立好的表。就可以找对应的元素。
	 * 通过数组的形式定义要查询的表格
	 */
	public static void toHex_2(int num) {
		//字符数组在内存中的默认初始化值是Unicode码'\u0000',代表空格的涵义
		char[] arr = new char[8];//建立数组用于存储转换后的十六进制数的各位
		//建立用于查询的表
		char[] chs = {'0','1','2','3',
					 '4','5','6','7',
					 '8','9','A','B',
					 'C','D','E','F'};
		int pos = 0;
		
		while(num!=0) {
			int temp = num&15;//用temp来临时保存我们所获取的4位
			arr[pos++] = chs[temp];//注意此处这种pos++的用法
			num = num>>>4;
		}
			
//		showArray(arr);
		//当然,我们也可以不使用showArray方法,直接for循环,从pos的位置开始反向打印,这是课程内老师所给的方法
		System.out.print("十六进制形式为:0x");
		for(int x=pos-1; x>=0 ;x--) {//注意最后pos在判断num之前还会再自加一次,因此pos自减一
			System.out.print(arr[x]);
		}
		
	}
	
	public static void showArray(char[] arr) {
		System.out.print("十六进制形式为:0x");
		for(int x=arr.length-1; x>=0 ;x--) {
			if(arr[x] != '\u0000') {//当数组内的值不为'\u0000',说明有保存值,将其打印
				System.out.print(arr[x]);
			}
		}
	}
}	

  结果如下:

60的二进制形式为111100
-6的二进制形式为:11111111111111111111111111111010
十六进制形式为:0x3C
十六进制形式为:0x3C
//两个取十六进制的方法对负数依然适用,第一个方法中,十进制转二进制的负数,必须先求负数的绝对值的二进制,再将其转换为补码,第二个查表的方法就可以直接将负数的十进制转二进制

  查表法十进制转二进制,八进制,十六进制的优化——将2个表的共性抽取出来

import java.util.*;
public class SortTest {

	public static void main(String[] args) {
		toBin(60);
		System.out.println();
		toOct(60);
		System.out.println();
		toHex(60);
		
	}
	/*
	 * 十进制转二进制
	 */
	public static void toBin(int num) {
		//直接调用trans方法,赋值即可
		trans(num,1,1);
	}
	/*
	 * 十进制转八进制
	 */
	public static void toOct(int num) {
		//直接调用trans方法,赋值即可
		trans(num,7,3);//三个二进制位等于一个八进制位
	}
	/*
	 * 十进制转二进制
	 */
	public static void toHex(int num) {
		//直接调用trans方法,赋值即可
		trans(num,15,4);
	}
	
	/*
	 * 查表法十进制转二进制,八进制,十六进制的优化——将2个表的共性抽取出来
	 * 先创建一个总体的转化方法,给其他进制转换方法调用
	 * 不直接在main函数中调用,这样代码显得更加合理有序
	 */
	public static void trans(int num,int base,int offset) {//base代表&的数不一样,offset代表偏移的位数不一样
		if(num == 0)
			System.out.println(0);
		char[] arr = new char[32];
		char[] chs = {'0','1','2','3',
					 '4','5','6','7',
					 '8','9','A','B',
					 'C','D','E','F'};
		int pos = 0;
		
		while(num!=0) {
			int temp = num&base;//用temp来临时保存我们所获取的4位
			arr[pos++] = chs[temp];//注意此处这种pos++的用法
			num = num>>>offset;
		}
			
		for(int x=pos-1; x>=0 ;x--) {//注意最后pos在判断num之前还会再自加一次,因此pos自减一
			System.out.print(arr[x]);
		}
		
	}
}	

5、二维数组
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
		int[][] arr = new int[3][4];
		System.out.println(arr);
		System.out.println(arr[0]);
	}

  结果是

[[I@7852e922
[I@4e25154f
//“[[”表示二维数组,“I”表示int类型,@后面是二维数组在内存中的地址
//下面的是二维数组内一维数组的地址
public static void main(String[] args) {
		int[][] arr = new int[3][];
		System.out.println(arr);
		System.out.println(arr[0]);
		arr[0] = new int[3];
		arr[1] = new int[1];
		arr[2] = new int[2];
		
		System.out.println(arr.length);//打印是二维数组的长度=3
		System.out.println(arr[0].length);//打印二维数组中第一个一维数组长度
	}

  结果是

[[I@7852e922
null
3
3

//“[[”表示二维数组,“I”表示int类型,@后面是二维数组在内存中的地址
//下面的二维数组内一维数组没有初始化,故系统默认初始化为空null,不会给它分配具体的地址
public static void main(String[] args) {
		int[][] arr = {{1,4,7,4},{1,2,3,2},{1,1,4,4}};
		
		//求二维数组所有元素的和
		int sum = 0;
		for(int x=0; x<arr.length ;x++) {
			for(int y=0; y<arr[x].length ;y++) {
				sum += arr[x][y];
			}
		}
		System.out.println("二维数组所有元素的和为"+sum);
		
	}

  结果是

二维数组所有元素的和为34

6、数组补充
  知识点1

//1. 静态初始化标准格式可以拆分成为两个步骤。
//2. 动态初始化也可以拆分成为两个步骤。
//3. 静态初始化一旦使用省略格式,就不能拆分成为两个步骤了。

// 静态初始化的标准格式,可以拆分成为两个步骤
        int[] arrayB;
        arrayB = new int[] { 11, 21, 31 };

        // 动态初始化也可以拆分成为两个步骤
        int[] arrayC;
        arrayC = new int[5];

        // 静态初始化的省略格式,不能拆分成为两个步骤。
//        int[] arrayD;
//        arrayD = { 10, 20, 30 };

  知识点2

/*
使用动态初始化数组的时候,其中的元素将会自动拥有一个默认值。规则如下:
如果是整数类型,那么默认为0;
如果是浮点类型,那么默认为0.0;
如果是字符类型,那么默认为'\u0000';unicode中字符类型的默认值,打印不可见
如果是布尔类型,那么默认为false;
如果是引用类型,那么默认为null。

注意事项:
静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成为了大括号当中的具体数值。
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值