java数组排序
数组的初始化方法
-
数组必须要经过初始化之后才能使用
-
数组初始化就是为数组中的元素分配内存空间,并且为每个数组元素赋值
-
数组初始化的方式:动态初始化、静态初始化
-
动态初始化:由我们来定义数组长度,让系统来赋初始值
-
静态初始化:由我们来赋值,系统计算数组长度
int[] arr1 = new int[5]; //动态初始化,整型数组默认初始值为0
int[] arr2 = new int[]{1,2,3,4,5}; //静态初始化
int[] arr3 = {1,2,3,4,5}; //静态初始化的简写方式
二分查找
-
前提条件:查询数据所在的数组必须要是一个有序数组
-
二分查找:当需要在数组中查询一个数时,从数组的中间位置开始查,
1. 如果查询的数 > 数组中间位置的数,那么就在数组后半部分查找,在数组的后半部分取一个中间位置的数…
2. 如果查询的数 < 数组中间位置的数,那么就在数组前半部分查找,在数组的前半部分取一个中间位置的数…
public static void main(String[] args) {
int[] arr = {10,20,30,50,60,70,80,90,150};
System.out.println("请输入你想查找的数字:");
int n = new Scanner(System.in).nextInt();
//定义一个二分查找的方法
int index = getIndex(arr,n);
System.out.println(index);
}
private static int getIndex(int[] arr, int ele) {
int maxIndex = arr.length - 1; //数组的最高位
int minIndex = 0; //数组的最低位
int centerIndex = (maxIndex - minIndex)/2; //数组的中间位置
while(minIndex <= maxIndex){
if( ele == arr[centerIndex]){
return centerIndex;
}else if(ele > arr[centerIndex]){
//如果查询的数 > 数组中间位置的数,改变数组最低位
minIndex = centerIndex + 1;
}else if(ele < arr[centerIndex]){
//如果查询的数 < 数组中间位置的数,改变数组最高位
maxIndex = centerIndex - 1;
}
//再用最新的高低位取中间位
centerIndex = (maxIndex - minIndex)/2;
}
return -1;
}
冒泡排序
-
冒泡排序原理:从数组中的第一个元素开始,两两进行对比,大的元素往后面放,经过一轮比较之后,最大的元素就会出现在数组的最后面
-
列如数组:{10 , 5 , 9 , 4 , 18 , 65 , 41 }
-
拿第一个位置上的元素与第二个位置上的元素进行比较,大的元素放后面{5 , 10 , 9 , 4 , 18 , 65 , 41 }
-
再拿比较之后的第二个位置上的元素与第三个位置上的元素进行比较,大的元素放后面{5 , 9 , 10 , 4 , 18 , 65 , 41 }
-
经过一轮比较之后,最大的元素就会出现在数组的最后面{5 , 9 , 4 , 10 , 18 ,41 , 65}
import java.util.Arrays;
public class BubblingSort {
public static void main(String[] args) {
/**冒泡排序原理:
* 从数组中的第一个元素开始,两两进行对比,大的元素往后面放
* 经过一轮比较之后,最大的元素就会出现在数组的最后面
*/
int[] arr = {10,5,9,4,18,65,41,24,23};
for(int j = 0;j < arr.length;j++){
for(int i = 0;i < arr.length-1-j;i++){
if(arr[i] > arr[i+1]){
int t = arr[i];
arr[i] = arr[i+1];
arr[i+1] = t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
选择排序
- 选择排序原理: 从第一个元素开始,依次和后面的元素进行比较,将小的元素往前面放,经过一轮比较之后,最小的元素就会出现在数组的最前方;
列如数组:{10 , 5 , 9 , 4 , 18 , 65 , 41 },
- 第一轮比较:
- 拿第一位 10 先跟第二位 5 比较,小的放前面 {5 , 10 , 9 , 4 , 18 , 65 , 41 }
- 再拿 第一位 5 跟 第三位 9 比较,小的放前面{5 , 10 , 9 , 4 , 18 , 65 , 41 }
- 经过一轮比较之后,最小的元素就会出现在数组的最前方{4 , 10 , 9 , 5 , 18 , 65 , 41 }
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int[] arr = {10,5,4,58,95,43,21,62,71,1,0};
for(int j = 0;j < arr.length - 1 ;j++){
for(int i = j + 1;i < arr.length ; i++){
if(arr[i] < arr[j]){
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
插入排序
-
列如数组:{10 , 5 , 9 , 4 , 18 , 65 , 41 }
-
将数组中的元素,依次插入到合适的排序位置
-
插入第一个元素 10 得到{10}
-
插入第二个元素 5 得到{5 ,10}
-
插入第二个元素 9 得到{5 ,9, 10}
-
…
import java.util.Arrays;
public class InsertSort {
public static void main(String[] args) {
int[] arr = {10,3,9,6,2,58,32,14,78};
for(int i = 1;i < arr.length ; i++){
int j = i;
while( j > 0 && arr[j-1] > arr[j] ){
int t = arr[j];
arr[j] = arr[j-1];
arr[j-1] = t;
j--;
}
}
System.out.println(Arrays.toString(arr));
}
}
希尔排序
-
基本思想:先将原表按增量ht分组,每个子文件按照直接插入法排序。同样, 拥下一个增量ht/2将文件再分为子文件,再直接插入法
排序。直到ht=1时整个文件排好序。
-
关键字:增量(步长)、间隔
-
列如数组:{10 , 5 , 9 , 18 , 65 , 41 ,30,55 }
-
第一步,选取增量为 4 ,间隔为4的元素分为一个小组,每个小组进行插入排序
初始数组 | 10 | 5 | 9 | 18 | 65 | 41 | 30 | 55 |
---|---|---|---|---|---|---|---|---|
第一组 | 10 | 65 | ||||||
第二组 | 5 | 41 | ||||||
第三组 | 9 | 30 | ||||||
第四组 | 18 | 55 | ||||||
第一步运行结果 | 10 | 5 | 9 | 18 | 65 | 41 | 30 | 55 |
- 第二步,选取增量为 4/2 ,间隔为2的元素分为一个小组,每个小组进行插入排序
第一步之后的数组 | 10 | 5 | 9 | 18 | 65 | 41 | 30 | 55 |
---|---|---|---|---|---|---|---|---|
第一组 | 9 | 10 | 30 | 65 | ||||
第二组 | 5 | 18 | 41 | 55 | ||||
第二步运行结果 | 9 | 5 | 10 | 18 | 30 | 41 | 65 | 55 |
- 第三步,选取增量为 2/2 ,间隔为1的元素分为一个小组,每个小组进行插入排序
第二步之后的数组 | 9 | 5 | 10 | 18 | 30 | 41 | 65 | 55 |
---|---|---|---|---|---|---|---|---|
第三步运行结果 | 5 | 9 | 10 | 18 | 30 | 41 | 55 | 65 |
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {1,7,2,3,5,4,6,0};
shellSort(arr);
}
public static void shellSort(int[] arr){
// 取增量h大小为数组长度的一半
for (int h = arr.length/2 ; h > 0 ; h = h/2){
// 从第h个元素 逐步对其所在组进行插入排序
for (int i = h ; i < arr.length ; i++){
int j = i;
int temp = arr[j];
if (arr[j] < arr[j - h]){
while (j - h >= 0 && temp < arr[j - h]){
arr[j] = arr[j-h];
j -= h;
}
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
- 增量选取为数组长度的一半,还不是很好,可以使用克努特序列进行优化
//定义一个间隔
int space = 1;
while(space <= arr.length/3){
//初始化数组间隔长度
space = space*3 +1;
}
- 将shellSort()方法进行优化
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {1,7,2,3,5,4,6,0};
shellSort(arr);
}
public static void shellSort(int[] arr){
//定义一个间隔
int space = 1;
while(space <= arr.length/3){
//初始化数组间隔长度
space = space*3 +1;
}
// 取增量h大小为克努特序列
for (int h = space ; h > 0 ; h = (h-1)/3){
// 从第h个元素 逐步对其所在组进行插入排序
for (int i = h ; i < arr.length ; i++){
int j = i;
int temp = arr[j];
if (arr[j] < arr[j - h]){
while (j - h >= 0 && temp < arr[j - h]){
arr[j] = arr[j-h];
j -= h;
}
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
快速排序
- 分治法:比大小,再分区
- 在数组中选取一个数作为基准数
- 分区:将比这个数大的放到右边,比这个基准数小的放在左边
- 再最左右区间重复第二个步骤,知道各个区间只有一个数
- 实现思路:挖坑填数
- 将基准数挖出形成第一个坑位
- 从后往前找比基准数小的数,挖出这个数填到第一个坑位里面,形成坑位二
- 从前往后找比基准数大或者等于基准数的元素,挖出这个数填到上一个坑位中,形成坑位三
- 重复执行2,3步骤
元素 | 15 | 18 | 9 | 22 | 19 | 7 | 16 | 17 | 14 |
---|---|---|---|---|---|---|---|---|---|
坑位 | 坑位1 | 坑位3 | 坑位5 | 坑位4 | 坑位2 | ||||
14 | 7 | 9 | 15 | 19 | 22 | 16 | 17 | 18 |
import java.util.Arrays;
public class QuickSort {
private static int partition(int[] arr, int start, int end) {
int i = start;
int j= end;
//1.将基准数挖出形成第一个坑位
int x = arr[start];
//4.重复执行2,3步骤
while(i<j){
//2.从后往前找比基准数小的数,挖出这个数填到第一个坑位里面,形成坑位二
while(arr[j]>=x && i<j){
j--;
}
if(i<j){
arr[i] = arr[j];
i++;
}
//3.从前往后找比基准数大或者等于基准数的元素,挖出这个数填到上一个坑位中,形成坑位三
while(arr[i]<x && i<j){
i++;
}
if(i<j){
arr[j] = arr[i];
j--;
}
}
arr[i] = x;
return i;
}
private static void quickSort(int[] arr, int start, int end) {
if(start < end){
int index = partition(arr,start,end);
quickSort(arr,start,index-1);
quickSort(arr,index+1,end);
}
}
public static void quickSort(int[] arr) {
int low = 0;
int high = arr.length-1;
quickSort(arr,low,high);
}
public static void main(String[] args) {
int arr[] = {6,25,32,12,13,24,62,56,45,52,19};
quickSort(arr);
System.out.println(Arrays.toString(arr));
}
}
归并排序
- 归并排序原理:归并排序是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序
- 代码实现:
- 申请空间,大小为两个半子集大小的空间,用来存放两个半子集排序合并后的数据
- 设定两个指针,最初位置分别为两个半子集的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针达到序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
import java.util.Arrays;
public class MergeSort {
public static int[] chaifen(int[] nums, int startIndex, int endIndex) {
int centerIndex = (startIndex + endIndex) / 2;
if (startIndex < endIndex) {
// 左边拆分
chaifen(nums, startIndex, centerIndex);
// 右边拆分
chaifen(nums, centerIndex + 1, endIndex);
// 左右归并
merge(nums, startIndex, centerIndex, endIndex);
}
return nums;
}
public static void merge(int[] nums, int startIndex, int centerIndex, int endIndex) {
int[] temp = new int[endIndex - startIndex + 1];
int i = startIndex;// 起始指针
int j = centerIndex + 1;// 结束指针
int k = 0;
// 把较小的数先移到新数组中
while (i <= centerIndex && j <= endIndex) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
// 把左边剩余的数移入数组
while (i <= centerIndex) {
temp[k++] = nums[i++];
}
// 把右边边剩余的数移入数组
while (j <= endIndex) {
temp[k++] = nums[j++];
}
// 把新数组中的数覆盖nums数组
for (int k2 = 0; k2 < temp.length; k2++) {
nums[k2 + startIndex] = temp[k2];
}
}
public static void main(String[] args) {
int[] nums = {6,25,32,12,13,24,62,56,45,52,19};
MergeSort.chaifen(nums, 0, nums.length-1);
System.out.println(Arrays.toString(nums));
}
}
基数排序
-
例如,对以下数组排序
-
从前向后遍历数组,按照各个元素个位上的数,将元素放到相应的桶里,如15,就放到标号为5的桶里
-
依次从将标号为0,1,2,3…的桶中的数拿出,放到数组中,得到数组
-
针对上面排序结束的数组,从前向后遍历数组,按照各个元素十位上的数,将元素放到相应的桶里
-
经过对十位操作后的数组变为:
-
针对上面经过对十位操作后的数组,从前向后遍历数组,按照各个元素百位上的数,将元素放到相应的桶里
-
最终得到最后的排序
import java.util.Arrays;
public class CardinalSort {
public static void main(String[] args) {
int[] arr = {10,3,5,6,456,45,21,365,258,3699,943,999,8882,158,4269};
Cardinalsort(arr);
System.out.println(Arrays.toString(arr));
}
private static void Cardinalsort(int[] arr) {
//定义一个桶,存放相应的数据
int[][] tempArr = new int[10][arr.length];
int maxIndex = getMax(arr);
//判断数组中的最大数的位数
int len = String.valueOf(maxIndex).length();
//定义一个统计数组,用来统计存入桶中元素的个数
int[] count = new int[10];
//根据最大数的位数设计循环的轮次
for(int i = 0,n = 1;i < len;i++,n*=10){
//判断数组中的每一位元素的个位上的值
for(int j = 0;j < arr.length;j++){
int ys = arr[j] / n % 10;
//根据判断余数上的值,将元素放入相应的桶中
tempArr[ys][count[ys]++] = arr[j];
}
int index = 0;
//将桶中的元素重新遍历到数组中
for(int m = 0;m < tempArr.length;m++){
if(tempArr[m] != null){
for(int k = 0;k < count[m];k++ ){
arr[index++] = tempArr[m][k];
}
count[m] = 0;
}
}
}
}
//定义一个方法,获取数组中的最大元素
private static int getMax(int[] arr) {
int maxIndex = arr[0];
for(int i = 1;i < arr.length;i++){
if(maxIndex<arr[i]){
maxIndex = arr[i];
}
}
return maxIndex;
}
}
堆排序
- 堆排序:堆排序(HeapSort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
- 堆排序思路:
- 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
- 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
- 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
import java.util.Arrays;
public class HeapSort {
public static void main(String []args){
int[] arr = {10,3,5,6,456,45,21,365,258,3699,943,999,8882,158,4269};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int []arr){
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
for(int k = i*2+1;k < length;k = k*2+1){
//从i结点的左子结点开始,也就是2i+1处开始
if(k+1 < length && arr[k] < arr[k+1]){
//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >temp){
//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//将temp值放到最终的位置
}
public static void swap(int []arr,int a ,int b){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}