/*
- 排序算法
- 通常排序的目的是为了快速查找
- 衡量排序算法的优劣
- 1,时间复杂度:分析关键字的比较次数和记录的移动次数
- 2,空间复杂度:分析排序算法需要多少辅助内存
- 3,稳定性:若两个记录A和B的关键字值相等,但排序后A,B的先后次序保持不变,则称这种排序算法是稳定的
*排序算法分类:内部排序,外部排序
*1,内部排序:排序过程不需要借助外部储器,所有排序操作在内存中完成
*2,外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助外部存储器,
*外部排序最常见的是多路归并排序,可以认为外部排序是由多次内部排序组成
*
*十大内部排序算法
*1选择排序
*直接选择排序,堆排序
*2,交换排序
*冒泡排序(最简单),快速排序(常用速度快)
*3,插入排序
*直接插入排序,折半插入排序,Shell排序(希尔排序)
*4,归并排序
*5,桶式排序
,6,基数排序
*
*算法的五大特征
*1,输入(Input) :有0个或多个输入数据,这些输入必须有清楚的描述和定义
*2,输出(Output) : 至少有一个输出结果,不能没有输出结果
*3,有穷性(Finiteness) :算法可以在有限步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的
*时间内完成
*4,确定性(Definiteness) : 算法中的每一步都有确定的含义,不会出现二义性
*5,可行性(Effectiveness) : 算法中的每一步都是清楚且可行的,都能让用户用纸笔计算而求出答案
*说明:满足确定性的算法也称为:确定性算法,现在有更广泛的概念,会考虑各种非确定算法,例如并行算法,概率算法
*等,另外也有并不要求终止的计算描述,这种描述也被成为过程(procedure).
*
*
*排序算法之间的比较
*1,从平均时间看,快速排序算法最佳但在最坏情况下不如堆排序与归并排序
*2,从算法简单性看,直接插入排序,直接选择排序与冒泡排序最简单,被认为是简单算法
*对于shell排序,堆排序,归并排序与快速排序,算法复杂,认为是复杂排序
*3,从稳定性看,直接插入,冒泡与归并排序是稳定的,直接选择,堆排序,快速排序与shell排序是不稳定的
*4,从待排序数据长度N来看,N较小时宜采用简单排序,较大时采用改进排序
*
*算法的选择
*1,当n较小时例如<=50 ,可采用直接插入或直接选择排序
*当记录规模较小时,直接插入排序较好,否则因为直接选择移动的记录数小于直接插入,应选择直接选择排序
*2,若数列初始状态基本有序(正序),则应用直接插入,冒泡或随机的快速排序
*3,若数据规模较大,应用时间复杂度为nlogn的算法如快速排序,堆排序,归并排序
*
*Arrays工具类的使用
*java.util.Arrays 中提供了数组的输出,填充,赋值,反转,二分查找,排序等功能
*可以查询API文档
*/
/*
- 冒泡排序
- 简介:重复游走要排序的数列,一次比较两个元素,如果顺序错误就把他们交换过来
- 排序思想:
- 1,比较相邻的元素,如果第一个比第二个更大(升序情况),就交换两个的顺序
- 2,对每一个相邻元素做同样的工作,从开始第一对到结尾的最后一对,这个步骤完成后,结尾的数就是最大的。
- 3,针对所有元素重复上一个步骤,除了最后一个
- 4,对越来越少的数据重复以上步骤,直到没有任何一对数字需要调换位置
- 直接选择排序
- 1,比较第一个元素和第二个元素,如果第二个比第一个小则交换位置
- 2,再比较第一个和第三个一直到最后一个,这样第一个元素位置就是数组的最小值
- 3,对第二个位置采用以上步骤,保证第二个元素的位置是除了第一个元素最小的
- 4,重复以上方式直到最后一个位置
- 直接插入排序
- 1,比较第一个和第二个元素,如果第二个元素小于第一个则交换位置,形成一个长度为2的有序数列
- 2,比较第三个元素和第二个元素的大小,如果小与第二个元素则向前比较,直到找到不小于前一个元素的位置。
- 3,将此位置之后的元素依次向前移动一位,将第三个元素插入到此位置
- 4,重复以上步骤直到最后一位。
*/
/*
- 快速排序
- 快速排序比同为O(nlogn)的其他算法更快,常被采用,而且采用分治法的思想
- 由Tony Horare发明,是迄今为止内排序算法中最快的一种,属于交换排序的一种,是
- 冒泡排序的升级版。
- 排序思想:
- 1,从数列中挑选一个元素成为基准(pivot).
- 2,重新排序数列,所有元素比基准值小的放在基准值前,所有元素比基准值大的放在基准后
- 相同的数可以放在任意一边,这个分区结束后,该基准就处于数列的中间位置,这个步骤称为分区操作(partition).
- 3,递归(recursive)把小于基准值的子数列和大于基准值的子数列排序
- 4,递归的最底部情况是数列的大小是0或1,也就是永远被排序好了,,虽然一直递归下去,但算法总会结束,因为在每次迭代(iteration)
- 中,它至少会把一个元素摆到它最终的位置去。
- 数组中的常见异常
- 1,数组角标越界的异常:ArrayIndexOutOfBoundsException
- 角标超出数组的角标范围【0,length】
- 2,空指针异常:NullPointerException(常见)
- 1,情况1,数组没有初始化,或者数组栈空间新赋值为null,堆空间地址被擦除
- int[] arr = new int[3];
- arr = null;
- System.out.println(arr);//输出null
- System.out.println(arr[0]);//错误
- int[][] arr1 = new int[4][];
- System.out.println(arr[0]);//输出默认值null
- System.out.println(arr[0][0]);//错误
- 2,情况2,调用null
- String[] arr2 = new String[]{null,“A”,“B”,“C”};
- System.out.print(arr2[0]);//输出null
- System.out.print(arr2[0].toString());//调用null,错误
*/
package com.atguigu.contact;
import java.util.*;
public class Array4 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入随机数组的长度");
int length = scan.nextInt();
int[] array = new int[length];
for (int l = 0; l < array.length; l++) {
array[l] = (int)(Math.random() * 201 - 100);//随机数组范围【-100,100】
}
for (int l = 0;l < array.length;l++) {
System.out.print(array[l] + " ");
}
System.out.println();
//直接插入排序
for (int i = 1; i < array.length; i++) {
int temp,k;
temp = array[i];//待比较的元素存入临时变量中
k = i;
for (;k > 0 && array[k - 1] >= temp;) {
array[k] = array[k - 1];//依次移动之前比temp大的元素到下一位置
k--;//角标每次自减一,直到array[k - 1]小于待比较大元素
}
array[k] = temp;//将要比较的元素插入位置k
}
for (int l = 0;l < array.length;l++) {
System.out.print(array[l] + " ");
}
System.out.println();
//直接选择排序
for (int i = 0; i < array.length -1; i++) {
int k = i;
int temp = 0;
for (int j = i; j < array.length; j++) {
if(array[j] < array[k]) {
k = j;//如果找到一个更小的值则K的角标变换为次值的角标,最后k是最小值的角标
}
}
temp = array[i];
array[i] = array[k];
array[k] = temp;//将找到的最小值与本次外层循环的第一个数值交换位置
}
for (int l = 0;l < array.length;l++) {
System.out.print(array[l] + " ");
}
System.out.println();
//冒泡排序
for (int i = 0; i < array.length -1; i++) {//外层循环控制轮数
for (int j = 0; j < array.length - 1 - i; j++) {//内层循环控制比较交换次数,每一轮去掉最后一位,需要-i
if(array[j] > array[j + 1]) { //array[j] < array[j + 1]表示降序
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;//如果顺序错误则交换位置
}
}
}
for (int l = 0;l < array.length;l++) {
System.out.print(array[l] + " ");
}
System.out.println();
//Arrays工具类的使用
//创建数组测试使用
System.out.println("请输入随机数组的长度");
int length1 = scan.nextInt();
int[] array1 = new int[length1];
for (int l = 0; l < array1.length; l++) {
array1[l] = (int)(Math.random() * 201 - 100);//随机数组范围【-100,100】
}
for (int l = 0;l < array1.length;l++) {
System.out.print(array1[l] + " ");
}
System.out.println();
int[] array2 = new int[0];//数组可以是空集,长度是0
int[] array3 = new int[] {1,2,3,4,5,6};
int[] array4 = new int[] {1,2,6,5,4,3};
int[] array5 = new int[] {23,-45,78,34,22,11,89,36,-34,-99,28,0,5,1};
//比较两个数组,判断是否相等
boolean mark0 = Arrays.equals(array3, array4);
boolean mark1 = Arrays.equals(array3, array4);//位置不同,数组也不同
System.out.println(mark0 + "" + mark1);
//输出数组元素
System.out.println(Arrays.toString(array2));
System.out.println(Arrays.toString(array3));
for (int i : array3) {//另一种输出方法
System.out.print(i + " ");
}
System.out.println();
//将指定数字填充到数组中
Arrays.fill(array3, 2);
System.out.println(Arrays.toString(array3));//数组中的所有元素都会被填充为指定数值
//对数组排序
Arrays.sort(array4);
System.out.println(Arrays.toString(array4));
Arrays.sort(array5);
System.out.println(Arrays.toString(array5));//底层调用双基准快速排序实现
//二分查找,输出被查找元素的角标,前提是数组已被排序好
int index = Arrays.binarySearch(array5, 11);
int index1 = Arrays.binarySearch(array5, 13);//返回正数代表角标,负数代表没找到不存在
System.out.println(index + "" + index1);
if(index1 >= 0) {
System.out.println(index1);
}else {
System.out.println("未找到");
}
//数组的复制
int[] array6 = new int[array5.length];
array6 = Arrays.copyOf(array5,array5.length);
System.out.println(Arrays.toString(array6));
int[] array7 = new int[array5.length];
array7 = array5.clone();//另一种方法
System.out.println(Arrays.toString(array7));
}
}