您的位置:首页 > 职场人生

黑马程序员——Java语言基础——02.java语言基础组成(4)数组及常用排序方法

2014-12-16 20:27 1006 查看

------- android培训java培训、期待与您交流!
----------

4-1 数组

4-1-1 数组的定义

概念:
同一种类型数据的集合。其实数组就是一个容器。

数组的好处:
可以自动给数组中的元素从0开始编号,方便操作这些元素。

格式1:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];

示例1:需要一个容器,但是不明确容器的具体数据。
int[] arr = new int[5];

格式2:需要一个容器,存储已知的具体数据。
元素类型[] 数组名 = new 元素类型[]{元素,元素,……};

示例:
int[] arr = new int[]{3,5,1,7};或int[]
arr = {3,5,1,7};

4-1-2 数组的内存分配及特点

int[] arr = new int[4];


内存分配图:



Java程序在运行时,需要在内存中分配空间。为了提高运算效率,又对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

栈内存:
用于存储局部变量,当变量所属的作用域一旦结束,所占空间会自动释放。

堆内存:
数组和对象,通过new建立的实例都存放在堆内存中。

每一个实体都有内存地址值
实体中的变量都有默认初始化值,根据类型的不同而不同。整数类型是0,小数类型是0.0或0.0f,boolean类型是false,char类型是'\u0000'。

如果将数组的引用实体设置为null,也就是实体不再被使用,那么会在不确定的时间内被垃圾回收器回收。

Java中的垃圾以及垃圾回收机制 (GC机制)

Java中的对象何时变成垃圾?

当一个堆内存中的对象在栈中没有引用指向它的时候,这个对象就被JVM视为垃圾

垃圾不会被立刻清理掉,而是在未知的时间点,JVM启动GC来回收这个对象所占用的空间。
Java中不用手动清除堆内存对象,只要将堆内存中的对象变成垃圾,这个垃圾对象就会被GC在某个不确定的时间自动清除掉。

4-1-3 数组操作常见问题

(1)数组脚标越界异常(ArrayIndexOutOfBoundsException)

int[] arr = new int[2];

System.out.println(arr[3]);
访问到了数组中的不存在的脚标时发生。

(2)空指针异常(NullPointerException)

int[] arr = null;

System.out.println(arr[0]);
arr引用没有指向实体,却在操作实体中的元素时。

4.1.4 数组常见操作

对数组操作最基本的动作就是存和取

核心思想:就是对角标的操作

第一种常见操作:获取最值(最大值,最小值)【必考,重要】

思路:

1、需要进行比较,并定义变量记录住每次比较后较大的值。

2、对数组中的元素进行遍历取出,和变量中记录的元素进行比较。

     如果遍历到的元素大于变量中记录的元素,就用变量该记录住大的值

3、遍历结果,该变量记录就是最大值。

获取最大值:

public static int getMax(int[] arr)
{
int max = arr[0];

for(int x=1; x<arr.length; x++)
{
if(arr[x]>max)
max = arr[x];
}
return max;
}

/*
获取最大值的另一种方式。
可不可以将临时变量初始化为0呢?可以。这种方式,其实是在初始化为数组中任意一个角标。
*/
public static int getMax_2(int[] arr)
{
int max = 0;

for(int x=1; x<arr.length; x++)
{
if(arr[x]>arr[max])
max = x;
}
return arr[max];
}

获取最小值:

/*
获取最小值。
*/
public static int getMin(int[] arr)
{
int min = 0;
for(int x=1; x<arr.length; x++)
{
if(arr[x]<arr[min])
min = x;
}
return arr[min];
}


第二种常见操作:排序(选择排序,冒泡排序)【必考】

选择排序:
思路:

1、首先拿数组第一个元素依次与除其自身外的其他每个元素顺序比较,如果第一个元素大于剩下的某个元素,就互换内容。

2、经过第一轮比较之后,此时第一个元素就是数组中最小的元素。然后再拿第二个元素与除第一个元素和其自身的元素进行比较,如果第二个元素大于剩下的某个元素,就互换内容。
3、依次类推,直到最后一个元素。

冒泡排序
思路:
1、首先在第一轮排序中,数组从第一个元素到倒数第二个元素依次与其右边的元素进行比较,如果左边的元素大于右边的元素,那么两个元素就互换。
2、经过第一轮比较,最大的元素就已经存储到数组最右边的结点中了。
3、第二轮排序则是从第一个元素到倒数第三个元素依次与其右边的元素进行比较,如果左边的元素大于右边的元素,那么两个元素就互换。
4、依照此方式,一直到只有第一和第二个元素互相比较而结束。
class PaiXu
{
//对数组进行冒泡排序和选择排序
public static void main(String[] args)
{
int[] arr = {4,5,7,1,2,3,9,8};
System.out.println("排序前数组");//我个逗比打错了System.out.println
Print(arr);//打印数组
//Xuanze(arr);
Maopao(arr);
System.out.println("排序后数组");
Print(arr);
}
//选择排序代码
public static void Xuanze(int[] arr)
{
for (int i=0; i<arr.length-1; i++)
{
for (int j=i+1; j<arr.length; j++)
{
if (arr[i]>arr[j])
//交换元素位置
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
//打印数组
public static void Print(int[] arr)
{
for (int i=0; i<arr.length; i++)
{
System.out.println("arr["+i+"]="+arr[i]);
}

}
//冒泡排序
public static void Maopao(int[] arr)
{
for (int i=0; i<arr.length-1; i++)
{
for (int j=0; j<arr.length-1-i; j++)
{
Swap(arr,j,j+1);
}
}
}
//替换功能抽出
public static void Swap(int[] arr,int i,int j)//三个变量
{
if (arr[i]>arr[j])
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}


第三种常见操作:折半查找(二分查找)

如果一个数组是无序的,那么可以通过简单遍历查找的方式查找到某个元素所在的角标。
但是如果一个数组是有序的(折半前先排序),那么就可以通过一种更高效的方式达到相同的目的,也就是二分查找。
思路:
1、设置三个变量记录角标:min、max、mid。min初始值为0,max为数组最大角标,mid为(max+min)/2。
2、查看mid角标的元素是否与待查找的值相等,如果相等,则直接返回角标值,程序终止执行。
3、如果待查找的值小于角标为mid的元素值,那么说明待查找的元素的位置可能在min与mid角标之间。设置max = mid - 1,mid = (max + min)/2,重复第1、2步的操作。
4、如果待查找的值大于角标为mid的元素值,那么说明待查找的元素的位置可能在mid与max角标之间。设置min = mid + 1,mid = (max + min)/2,重复第1、2步的操作。
5、如果数组中不存在待查找的元素,那么按照如上流程,最终min角标值会大于max角标值,此时返回-1。
import java.util.*;
class Half
{
public static void main(String[] args)
{
int[] arr = {10,9,3,4,5,6,7,8};
Arrays.sort(arr);
int[] arr1 = Arrays.copyOf(arr, arr.length);
for (int n : arr1)
{
System.out.println(n);
}
//int index = getKey(arr);
int mid = Half1(arr1,8);
System.out.println("key="+mid);

}

//普通查找
public static int getKey(int[] arr)
{
int key = 10;
for (int i=0; i<arr.length; i++)
{
if (key == i)
{
return i;
}
}
return -1;
}

//折半查找1
public static int Half(int[] arr, int key)
{
int min = 0;
int max = arr.length - 1;
int mid = (max + min)/2;
while (arr[mid] != key)
{
if (key > arr[mid])
min = mid + 1;
else if (key < arr[mid])
max = mid - 1;
if (min > max)
{
return -1;
}
mid = (max + min) / 2;
}
return mid;
}

//另一种折半查找
public static int Half1(int[] arr, int key)
{
int min = 0, max = arr.length, mid;
while (min <= max)
{
mid = (min+max)/2;
if(key > arr[mid])
min = mid + 1;
else if(key < arr[mid])
max = mid - 1;
else return mid;
}
return -1;
}

}

4-2 常见排序代码

感谢黑马网友的帖子,代码如下
/*
1、对给定数组进行排序。
{5,1,6,4,2,8,9}
//Arrays.sort(arr);//java中已经定义好的一种排序方式。开发中,对数组排序。要使用该句代码。
2、对给定的数组进行反转。
{3,1,5,6,2} --->
{2,6,5,1,3}
*/
class  ArraySort{
static int num=0;
public static void main(String[] args){
int[] arr1={5,1,6,4,2,7,10,12,3,8,4,9,13,22,56};

int[] arr2={5,1,6,4,2,7,10,12,3,8,4,9,13,22,56};
printArr(arr2);
mergeSort(arr2,0,arr2.length-1);
//quickSort(arr2,0,arr2.length-1);

printArr(arr2);
}

//反转数组
public static void reverseArray(int[] arr){
for(int start=0,end=arr.length-1;start<end;start++,end--)
swap(arr,start,end);
}

/*
选择排序。
思路:遍历除最后一个元素的所有元素,依次拿每个元素与后面的每一个元素进行比较
如果大于后面的元素则进行交换。
*/
public static void selectSort(int[] arr){
for(int i=0;i<arr.length-1;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){
swap(arr,i,j);
//num++;
}
}
}
}

/*
冒泡排序
思路:
从头到尾拿每一个元素(除最后一个)与后面相邻的元素进行比较,
如果大于后面的元素则进行交换。这样最大值将到最后面,
忽略最后一个元素,重复上面的步骤直到完全排序。
*/
public static void bubbleSort(int[] arr){
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])
swap(arr,j,j+1);
}

//快速排序
/*
思路:1、用2个leftPos,rightPos指针,分别指向给定数组arr的首位置和尾位置。
2、记录该数组的首位置的值为基准值base
3、用右指针rightPos开始搜索向左搜索比基准值小的数,
搜索范围在左指针之的右边。找到第一个比基准值小的数后,
右指针指向该位置并将该位置的值arr[rightPos]赋给左指针所指向位置的值arr[leftPos]
4、用左指针leftPos开始搜索向右搜索比基准值大的数,
搜索范围在右指针之前的左边。找到第一个比基准值大的数后,
右指针指向该位置并将该位置的值arr[leftPos]赋给左指针所指向位置的值arr[rightPos]
5、重复3、4步骤,直到左右2指针指向同一位置,将基准值base赋给该位置的值。
6、此时,大于基准值的数都到了右边,小于基准值的数都到了左边
7、若基准值左边还有数,则将左边的所有数作为一个数组重复1-5这5个步骤。
8、若基准值右边还有数,则将右边的所有数作为一个数组重复1-5这5个步骤。
*/
public static void quickSort(int[] arr, int start, int end) {
int leftPos=start,rightPos=end,base=arr[start];
while(leftPos<rightPos){
while(arr[rightPos]>=base && leftPos<rightPos) rightPos--;
arr[leftPos]=arr[rightPos];
while(arr[leftPos]<=base && leftPos<rightPos) leftPos++;
arr[rightPos]=arr[leftPos];
}
arr[leftPos]=base;
//printArr(arr);
//System.out.println("start:"+start+",end:"+end);
if(leftPos-start>=3 ||(leftPos-start==2 && arr[leftPos-1]==arr[leftPos-2]))
quickSort(arr,start,leftPos-1);
if(end-rightPos>=3 ||(end-rightPos==2 && arr[rightPos+1]==arr[rightPos+2]))
quickSort(arr,rightPos+1,end);

}
//插入排序
/*
具体算法描述如下:
⒈ 从第一个元素开始,该元素可以认为已经被排序
⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描
⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置
⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
⒌ 将新元素插入到下一位置中
⒍ 重复步骤2~5
调用方法为:insertSort(arr,0,1);//起始为0,增量为1
*/
public static void insertSort(int[] arr,int start,int increment) {
if(arr.length<2) return;
int i,j,insert;
for(i=start+increment;i<arr.length;i+=increment){//每次循环拿该元素与前面所有元素进行比较
insert=arr[i];
for(j=i-increment;j>=0 && arr[j]>insert;j-=increment){
arr[j+increment]=arr[j];
}
if(j!=i-increment) arr[j+increment]=insert;
}
}
//希尔排序
/*
1、初始增量为数组长度的一半,每次循环完成增量变为原来的一半
2、划分出编号为0~increment-1的组
3、每组是以编号i开始,间隔为increment的所有元素
下面对每一组进行"插入排序"(详见上一种排序方法)
*/
public static void shellSort(int[] arr) {
if(arr.length<2) return;

for(int increment=arr.length/2;increment>=1;increment/=2)
for(int i=0;i<increment;i++)
insertSort(arr,i,increment);
}

//归并排序
/*
归并操作的工作原理如下:
1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2、设定两个指针,最初位置分别为两个已经排序序列的起始位置
3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4、重复步骤3直到某一指针超出序列尾
5、将另一序列剩下的所有元素直接复制到合并序列尾
*/
private static void merge(int[] arr,int start1,int start2,int end){
int[] tmp = new int[end-start1+1];
int i=start1,j=start2,num=0;
while(i<start2 && j<=end){
if(arr[i]<=arr[j])
tmp[num++]=arr[i++];
else
tmp[num++]=arr[j++];
}
while(i<start2)
tmp[num++]=arr[i++];
while(j<=end)
tmp[num++]=arr[j++];
System.arraycopy(tmp,0,arr,start1,tmp.length);
for(int a=0;a<start1*2;a++)
System.out.print(" ");
printArr(tmp);
//arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
}
//归并排序
/*
将一个数组不断的递归分解成以中间值为基准的左右两部分
直到每个部分只剩下一个元素,然后不断的进行归并操作。
*/
public static void mergeSort(int[] arr, int start, int end){
if(start<end){
int mid=(start+end)/2;
mergeSort(arr,start,mid);
mergeSort(arr,mid+1,end);
merge(arr,start,mid+1,end);
}
}

public static void printArr(int[] arr){
System.out.print("[");
for(int i=0;i<arr.length;i++){
if(i!=arr.length-1) System.out.print(arr[i]+",");
else System.out.print(arr[i]+"]");
}
System.out.println();
}

public static void swap2(int[] arr,int i,int j){
arr[i]=arr[i]^arr[j];
arr[j]=arr[i]^arr[j];
arr[i]=arr[i]^arr[j];
}
public static void swap(int[] arr,int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}


------- android培训java培训、期待与您交流!
----------

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: