数组的排序算法
算法=数据结构+程序代码
1.排序:
假设含有n个记录的序列为{R1,R2,…Rn},其相应的关键字序列为{K1,K2,…,Kn}。将这些记录重新排序为{Ri1,Ri2,…Rin},使得相应的关键字值满足条Ki1<=Ki2<=…<=Kin,这样的一种操作称为排序。
通常来说,排序的目的是快速查找,例如二分查找。
2.衡量排序算法的优劣:
(1)时间复杂度:分析关键字的比较次数和记录的移动次数
(2)空间复杂度:分析排序算法中需要多少辅助内存
(3)稳定性:若两个记录A和B的关键字值相同,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。
3.排序算法分类:
内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成
外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成。
4.算法的5大特性
输入:有0个或多个输入数据,这些输入必须要有清楚的描述和定义
输出:至少有1个或者多个输出结果,不可以没有输出结果
有穷性(有限性):算法在有限的步骤之后会自动结束,而不会死循环,并且每一个步骤可以在可接受的时间内完成
确定性(明确性):算法中的每一步都有明确的含义,不会出现二义性
可行性(有效性):算法的每一步都是清楚可行的,能让用户使用纸笔计算出答案。
5.十大内部排序算法
选择排序:直接选择排序、堆排序
交换排序:冒泡排序、快速排序(这两种会写出代码)
插入排序:直接插入排序、折半插入排序、Shell排序
归并排序:
桶排序:
基数排序:
5.1快速排序算法
快排思想:
1)先从数列中取出一个数作为基准数,记为key。
2)移动下标,将不小于x的数全放到它的右边,不大于x的数全放到它的左边(这样key的位置左边的没有大于key的,右边的没有小于key的,只需对左右区间排序即可)
3)再对左右区间重复第二步,直到各区间只有一个数
public class QuickSortTest {
public static void main(String[] args) {
int[] arr=new int[] {12,5,8,9,10};
System.out.println("排序前的结果是:");
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+"\t");
}
System.out.println();
quickSort(arr,0,arr.length-1);
System.out.println("排序后的结果是:");
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+"\t");
}
}
public static void quickSort(int[] arr,int left,int right) { //快速排序
if(arr==null || left>right) {
return ;
}
if(left > right) {
return ;
}
int l=left;
int r=right;
int key=arr[left];
while(l != r) {
while(arr[r]>=key && l<r) { //左移
r--;
}
while(arr[l]<=key && l<r) { //右移
l++;
}
if(l<=r) { //交换l和r的位置
int temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
}
}
arr[left]=arr[l];
arr[l]=key;
quickSort(arr,l+1,right); //递归对右侧的子序列排序
quickSort(arr,left,l-1); //递归对左侧的子序列排序
}
}
5.2 选择排序算法
选择排序思想:
1)在未排序的n个数(a[0]~a[n-1])中找到最小值,将它与a[0]交换;
2)在剩下未排序的n-1个数(a[1]~a[n-1])中找到最小值,将它与a[1]交换;
…
依次如下,在第n-1步,在未排序的2个数(a[n-2]~a[n-1])中找到最小值,将它与a[n-2]交换。
public class SortTest {
public static void main(String[] args) {
int[] arr = {12, 5, 8, 9, 4, 10, 56, -8};
System.out.println("排序前的数组是:");
System.out.println(Arrays.toString(arr));
int[] sort = selectSort(arr);
System.out.println("排序后的数组是:");
System.out.println(Arrays.toString(sort));
}
//选择排序算法
public static int[] selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int index = i; //index用于存放最小值所在的下标
for (int j = i + 1; j < arr.length; j++) { //寻找最小值所在的下标
if (arr[index] > arr[j]) {
index = j;
}
}
int temp = arr[i]; //最小元素与下标为i的元素交换
arr[i] = arr[index];
arr[index] = temp;
}
return arr;
}
}
5.3 冒泡排序
冒泡排序思想:
从第一个元素开始比较相邻的两个元素,如果第一个比第一个大或小,就互换它们的位置,这样先比较完一次,然后抛弃最大或最小的继续比较,直到排序完成。
public class SortTest {
public static void main(String[] args) {
int[] arr = {12,5,8,9,4,10,56,-8};
System.out.println("排序前的数组是:");
System.out.println(Arrays.toString(arr));
int[] sort = bubbleSort(arr);
System.out.println("排序后的数组是:");
System.out.println(Arrays.toString(sort));
}
//冒泡排序算法
public static int[] bubbleSort(int[] arr){
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){ //交换相邻元素的位置
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
}
排序算法总结:
性能比较:
1.从平均时间而言:快速排序最佳。
2.从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。
3.从稳定性看:直接插入排序、冒泡排序和归并排序时稳定的;而直接选择排序、快速排序、Shell排序和堆排序是不稳定排序
4.从待排序的记录数n的大小看,n较小时,宜采用简单排序;而n较大时宜采用改进排序。
二. 数组中工具类Arrays的使用
Arrays类位于 java.util 包中,主要包含了操作数组的各种方法。
1.Arrays.equals()判断两个数组是否相同,相同为true,不同为false
2.Arrays.toString()输出数组信息
3.Arrays.fill()将指定元素填充进数组arr2,实际就是替换全部的元素
4.Arrays.sort()对数组排序
5.数组二分法查找元素,返回一个值,整数说明找到,负数说明未找到
import java.util.Arrays;
/*
* Arrays工具类的使用:import java.util.Arrays;
*/
public class ArrayTest {
public static void main(String[] args) {
int[] arr1 = new int[] {1,2,3,4};
int[] arr2 = new int[] {1,2,4,3};
//1.Arrays.equals()判断两个数组是否相同,相同为true,不同为false
System.out.println(Arrays.equals(arr1,arr2));
//2.Arrays.toString()输出数组信息
System.out.println(Arrays.toString(arr1));
//3.Arrays.fill()将指定元素填充进数组arr2,实际就是替换全部的元素
Arrays.fill(arr2,10);
System.out.println(Arrays.toString(arr2));
//4.Arrays.sort()对数组排序
int[] arr3 = new int[] {15,8,6,54,9};
Arrays.sort(arr3);
System.out.println(Arrays.toString(arr3));
//5.数组二分法查找元素,返回一个值,整数说明找到,负数说明未找到
int index = Arrays.binarySearch(arr3,10);
System.out.println(index);
}
}
此处只列举一部分,具体的查看jdk_1.8帮助文档
三. 数组中常见的异常
1.数组(下标)索引越界:
数组索引范围:[0,arr.length-1]
原因:
遍历操作或根据索引使用数组元素时,找出此范围就会下标越界。
2.空指针异常:
原因:
(1)对象或者数组赋值为null,就调用方法或属性
(2)二维数组内层数组未定义就使用