数组排序-八种数组的排序方法解释说明案例
基本查找
直接通过for循环,获得数值所对应的索引值。
二分查找
通过二分法来查找数据能能大大的提高效率,数组要求必须是按顺序排序。寻找数据时从中间开始判断,如果数据比中间值小,则查找范围最大值缩小为中间索引-1,反之,查找范围最小值缩小为中间索引+1,重复操作获取数值所对应的索引。
//二分法
//把数据分成两半进行排序
public class ArrayDichotomy {
public static void main(String[] args) {
int arry[] = new int[]{10,20,30,40,50,60,70,80,90};
int index = getIndex(arry, 10);
System.out.println(index);
}
private static int getIndex(int[] arry, int i) {
int minIndex=0;
int maxIndex=arry.length-1;
int centerIndex=(minIndex+maxIndex)/2;
while (minIndex<=maxIndex){
if (i == arry[centerIndex]){
return centerIndex;
}else if (i>arry[centerIndex]){
minIndex=centerIndex+1;
}else if (i<arry[centerIndex]){
maxIndex=centerIndex-1;
}
centerIndex=(minIndex+maxIndex)/2;
}
//没找到返回-1
return -1;
}
}
①冒泡排序
Java最经典的排序方式,简单来说就是每一个数据与后面的数据两两进行比较,如果比它大或小就换位置,一轮后最大或者最小的数就出现在最后一个数,反复循环,可以把数据从大到小或从小到大进行排列。
//冒泡法
//数据两两比较,大的数据和小的数据换位置
public class ArrayBubble {
public static void main(String[] args) {
int[] arry = new int[]{1,4,543,67,268,7845,-1};
for (int i = 0; i < arry.length-1; i++) {
for (int j = 0; j < arry.length-1-i; j++) {
if (arry[j]>arry[j+1]){
int t = arry[j+1];
arry[j+1] = arry[j];
arry[j] = t;
}
}
}
System.out.println(Arrays.toString(arry));
}
}
②选择排序
对数组元素直接进行比较,用第一个数依次和后面的数比较,如果数值比第一个数小则交换位置,一轮后数组中的最小值出现在第一位,重复循环,可以把数组从小到大进行排序。
//选择排序
//从0开始,依次和后面的元素进行比较,小的放前面,一轮后最小的在最前面
public class ArrayChoose {
public static void main(String[] args) {
int[] array = new int[]{24,69,80,53,45};
for (int j = 0; j < array.length - 1; j++) {
for (int i = 1+j; i < array.length; i++) {
if (array[j]>array[i]){
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
System.out.println(Arrays.toString(array));
}
}
③直接插入排序
把第一个数据看成一个数组,里面只有一个元素,然后循环循环整个数组,当发现第二个元素比第一个小时,把元素插入到第一个元素的左边,然后插入第三个元素时依次和前面的元素判断,判断是插入两者的左边、中间、右边,反复上述过程,完成数组的排序。
//直接插入排序
//将一个记录插入到长度为m的有序表中,使之保持有序
public class ArrayDirectInsertion {
public static void main(String[] args) {
int[] array = new int[]{49,38,358,541,3896};
//方法一
//循环表示要进行的次数
/*for (int i = 1; i < array.length; i++) {
//这里定义j的存在是因为当元素数量大于2时,就要判断三者之间的关系,而不仅仅于一个元素的左还是右
int j=i;
//如果数据比第一个小,两个互换位置
while (j>0&&array[j]<array[j-1]){
int t=array[j];
array[j]=array[j-1];
array[j-1]=t;
j--;
}
}*/
//方法二
for (int i = 1; i < array.length; i++) {
for (int j = i; j >0 ; j--) {
if (array[j]<array[j-1]){
int t=array[j];
array[j]=array[j-1];
array[j-1]=t;
}
}
}
System.out.println(Arrays.toString(array));
}
}
④希尔排序
希尔排序是对直接插入排序的优化,简单来说,就是以一定的间隔来进行元素大小判断,从而简化一些大小判断过程。核心思想就是合理的选取增量,就会让序列大致有序。
//希尔排序
//对直接插入排序的优化 核心思想就是合理的选取增量 就会让序列大致有序
//然后再不断的缩小增量,进行插入排序,直到增量为1
import java.util.Arrays;
public class ArrayShell {
public static void main(String[] args) {
int[] array = new int[]{46,55,13,42,17,94,5,70};
//Knuth 克努特 序列选取间隔 提高效率
int jiange = 1;
while (jiange<= array.length/3){
jiange = jiange*3+1;
}
for (int h =jiange; h>0; h=(h-1)/3){
for (int i = h; i <array.length; i++) {
for (int j = i; j >h-1 ; j-=h) {
if (array[j]<array[j-h]){
int t=array[j];
array[j]=array[j-h];
array[j-h]=t;
}
}
}
}
System.out.println(Arrays.toString(array));
}
}
⑤快速排序
1.从数组中取出一个数,作为基准数
2.分区:将比这个数大或等于的数全放到他的右边,小于他的数放到他左边
3.重复第二步,直到只有一个数
//快速排序算法
//分治法:比大小,再分区
public class ArrayQuick {
public static void main(String[] args) {
int[] arr = new int[]{10,3,5,6,1,0,100,40,50,8};
quickSort(arr,0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr,int start,int end) {
//找出分左右两区的索引位置,然后对左右两区进行递归调用
if (start<end){
int index = getIndex(arr, start, end);
quickSort(arr,start,index-1);
quickSort(arr,index+1,end);
}
}
//将基准数挖出形成第一个坑
//由后向前找比他小的数,找到后挖出此数填到前一个坑中
//由前向后找比他大或等于的数,找到后也挖出此数填到前一个坑中
//执行2.3步骤
private static int getIndex(int[] arr, int start, int end) {
int i = start;
int j = end;
int x = arr[i];
while(i<j){
//由后向前找比他小的数,找到后挖出此数填到前一个坑中
while (i<j&&arr[j]>=x){
j--;
}
if (i<j){
arr[i]=arr[j];
//坑位已经填入数据,向后移动位置
i++;
}
//由前向后找比他大的数,找到后挖出此数填到前一个坑中
while (i<j&&arr[i]<x){
i++;
}
if (i<j){
arr[j]=arr[i];
j--;
}
}
arr[i]=x;//把基准数填到最后一个坑中
return i;
}
}
⑥归并排序
//归并排序
public class ArrayMerge {
public static void main(String[] args) {
//原始待排序数组
int[] arr = {10,30,2,1,0,8,7,2,5,10,20};
//int[] arr = {4,5,7,8,1,2,3,6};
//拆分
chaiFen(arr,0,arr.length-1);
//归并
//guiBing(arr, 0, 3, arr.length-1);
System.out.println(Arrays.toString(arr));
}
private static void chaiFen(int[] arr, int startIndex, int endIndex) {
//计算中间索引
int centerIndex = (startIndex+endIndex)/2;
if (startIndex<endIndex){
chaiFen(arr,startIndex,centerIndex);
chaiFen(arr,centerIndex+1,endIndex);
guiBing(arr,startIndex,centerIndex,endIndex);
}
}
private static void guiBing(int[] arr, int startIndex, int centerIndex, int endIndex) {
//定义一个临时数组
int[] tempArr = new int[endIndex-startIndex+1];
//定义左边数组起始索引
int i = startIndex;
//定义右边数组起始索引
int j = centerIndex+1;
//定义临时数组的起始索引
int index = 0;
//比较左右两个数组的元素大小,往临时数组放
while (i<=centerIndex&&j<=endIndex){
if (arr[i]<=arr[j]){
tempArr[index] = arr[i];
i++;
}else {
tempArr[index] = arr[j];
j++;
}
index++;
}
//处理剩余元素
while (i<=centerIndex){
tempArr[index] = arr[i];
i++;
index++;
}
while (j<=endIndex){
tempArr[index] = arr[j];
j++;
index++;
}
// System.out.println(Arrays.toString(tempArr));
//将临时数组数据区取到原数组中
for (int k = 0; k < tempArr.length; k++) {
arr[k+startIndex] = tempArr[k];
}
}
}
⑦基数排序
//基数排序
public class ArrayRadix {
public static void main(String[] args) {
//基数排序通过分配再收集的方式进行排序
int[] arr = {2,1,5,21,43,44,32,846,342234};
//待确定的排序伦次
//获取数组中的最大值
//int max = getMax(arr);
//基数排序
sortArray(arr);
System.out.println(Arrays.toString(arr));
}
private static void sortArray(int[] arr) {
//定义二维数组,管理10个桶
int[][] tempArr = new int[10][arr.length];
//定义统计数组
int[] count = new int[10];
int max = getMax(arr);
int len = String.valueOf(max).length();
//循环伦次
for (int i = 0,n=1; i < len; i++,n*=10) {
for (int j = 0; j < arr.length; j++) {
//获取每个位上的数字
int last = arr[j]/n%10;
tempArr[last][count[last]++] = arr[j];
}
//取出元素
int index = 0;
for (int k = 0; k < count.length; k++) {
if (count[k]!=0){
for (int h = 0; h < count[k]; h++) {
//从桶中取出元素放回原数组
arr[index] = tempArr[k][h];
index++;
}
count[k] = 0;//清除上一次统计的个数
}
}
}
}
private static int getMax(int[] arr) {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max = arr[i];
}
}
return max;
}
}
⑧堆排序
//堆排序
//通过将待排序列构造成一个大顶堆,此时整个序列的最大值就是堆顶的根节点 反复重复获取次最大值 最后完成排序
public class ArrayHeap {
public static void main(String[] args) {
int[] arr = {1, 0, 6, 7, 2, 3, 4};
//调整成大顶堆的方法
//定义开始调整的位置
int startIndex = (arr.length-1)/2;
//循环开始
for (int i = startIndex; i >=0; i--) {
toMaxHeap(arr,arr.length,i);
}
// System.out.println(Arrays.toString(arr));
//上面操作把数组变成了大顶堆,把根元素和最后一个元素进行调换
for (int i = arr.length-1;i>0;i--){
//进行调换
int t = arr[0];
arr[0] = arr[i];
arr[i] = t;
//换完再把剩余元素调成大顶堆
toMaxHeap(arr,i,0);
}
System.out.println(Arrays.toString(arr));
}
//排序的数组 调整的元素个数 从哪里开始调整
private static void toMaxHeap(int[] arr, int size, int index) {
//获取左右字节的索引
int leftNodeIndex = index*2+1;
int rightNodeIndex = index*2+2;
//查找最大节点所对应的索引
int maxIndex = index;
if (leftNodeIndex<size&&arr[leftNodeIndex]>arr[maxIndex]){
maxIndex = leftNodeIndex;
}
if (rightNodeIndex<size&&arr[rightNodeIndex]>arr[maxIndex]){
maxIndex = rightNodeIndex;
}
//调换位置
if (maxIndex!=index){
int t = arr[maxIndex];
arr[maxIndex] = arr[index];
arr[index] = t;
//调换完之后可能影响到后面的子树,不是大顶堆,再次调换
toMaxHeap(arr,size,maxIndex);
}
}
}