java中数组的5种排序方法
文章目录
- java中数组的5种排序方法
- 前言
- 1.冒泡排序
- 2.选择排序
- 3.插入排序
- 4.快速排序
- 5.归并排序
- 后话
前言
- java中数组的冒泡,选择,插入,快速,归并排序的实现。
1.冒泡排序
实现思路:第一层循环表示循环的次数,即数组的长度 第二层循环中比较最两个左边两个数大小,右边大则交换,右边小则不动。
核心代码块
public int[] bubble(int[] arr) {
int tem = 0;
for (int j = 0; j < arr.length; j++) {
for (int i = 0; i < arr.length - j - 1; i++) { //不减1越界了!!
if (arr[i] > arr[i + 1]) {
tem = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = tem;
}
}
}
return arr;
}
上面的方法为产生随机数组的方法,下面方法为冒泡的方法
main方法
实现
2.选择排序
实现思路:具体实现待排序数据序列的第一个元素和这个序列中的其他所有元素比较,这样拿到最小值,就放在刚才这个待排序序列的第一个位置。
- 第一层循环:每循环一次确认一个arr[i]的位置(依次从左至右)循环arr.length次
- 第二层循环:每次循环用arr[i]与剩下的arr[i+1]到arr[arr.length] Ps(arr[j])的数字进行对比;
- 若arr[j]小于arr[i], int temp=arr[i];arr[i]=arr[j],arr[j]=temp; else,不操作
核心代码块
public int[] selectSort(int[] arr) {
for (int i = 0; i < arr.length; i++) { //从数组第一位循环到最后一位,一次从左至右确认最小值。
for (int j = i + 1; j < arr.length; j++) { //每次循环和数组中剩下的元素比较若小于则对换位置,若大于则不操作
if (arr[j] < arr[i]) { //判断大于还是小于
int temp = arr[i]; //设定临时地址存放arr[i];
arr[i] = arr[j]; //交换
arr[j] = temp; //交换
}
}
}
return arr;
}
实现
3.插入排序
实现思路:插入排序像是洗牌一样,在算法中的具体实现是:
- 从左至右从数组中拿出数字i记做temp。拿出的temp跟它左边的数字进行比较若左边的数字比它大则该数字向右挪一个位置。
- 依次循环,若遇到比他小的数字则跳出循环。因为左边的数字比他小右边的数字又都比它大则这就是temp当前该待的相对位置。
核心代码块
public int[] insertSort(int[] array) {
for(int i = 1;i<array.length;i++) { //直接让i=1了因为若是i从0开始左边没数可以比。没有必要
int temp = array[i]; //用一个临时地址记住array[i]的值,是因为array[i]会被动态的赋值。
int j; //在外面定义j是因为第二重循环结束时,还需要用到j这个局部变量。
for(j=i-1;j>=0;j--) { //循环的次数为array[i]左边的牌数。所以是j=i-1。循环到没牌时结束即0时。
if(array[j]>temp) { //必须跟temp比值,不能跟array[i]比。因为array[i]的值已经改变(变成array[j])
array[j+1]=array[j]; //必须是array[j]赋值给array[j+1] 不能是array[i]=array[j] 因为是比temp大的往上挪一位,若是用i表示就变成插入。
}else {
break; //若是temp比左边的牌大或是一样大,直接跳出第二重for循环。
}
}
array[j+1]=temp; //这里才是temp真正要插入的位置。因为循环结束j--了。所以需要加一,回到循环结束时j的位置插入temp。
}
return array;
}
实现
4.快速排序
实现思路:
- 每当传一个数组进来,先定义一个临时变量temp储存基准数据。一般这个数据设置为arr[left]。在定义一个左指针left,一个右指针right
- 先从后(right)开始扫描,若是扫描到的数据比temp大或等于则不需要交换,right–指针向后挪,直到扫描到一个小于temp的数据,跳出循环,进行交换。arr[left]=arr[right]。
- 在从左边开始扫描一样的原理,直到扫描到一个比temp大的数据跳出循环。arr[right]=arr[left]。这样一直循环直到left==right跳出大循环。这时temp左边的数都比它小,右边的数都比它大。
- 返回left或者right的值。再次的调用该方法直到只剩下单个元素时(left=right)必定有序。
核心代码块
public class QuickSort {
//这个方法用来把传进来的数组进行有序排序
public static int sort(int[] arr, int left, int right) { //left,right分别代表左右指针
int temp = arr[left]; //临时变量,用来储存基准数据
while (left < right) { //直到left<right 这时left已经等于right。两个指针已经重叠
while (left < right && arr[right] >= temp) { //若是扫描到的数据比temp大或等于则不需要交换,right--指针向前挪PS(同时也需要满足left < right指针一旦重叠就跳出)
right--;
}
arr[left] = arr[right]; //循环跳出证明已经遇到一个小于temp的数据了,交换即可。
while (left < right && arr[left] <= temp) { //若是扫描到的数据比temp小或等于则不需要交换,left++指针向前挪
left++;
}
arr[right] = arr[left]; //循环跳出证明已经遇到一个大于temp的数据了,交换即可。
}
arr[left] = temp; //这时left===right 令temp赋值arr[left/right]
return left; //返回temp现在的下标位置。用于等等调用自己
}
//这个方法用来把传进来的数组。调用sort方法相对排序。获得left为中点将数组分为两个相对"有序"的数组。调用自己一直拆分数组,边拆分边排序。
public void quickSort(int[] arr, int left, int right) {
if (left < right) { //递归终止条件,只剩一个元素时。
int mid = sort(arr, left, right); //调用sort方法,获得上次调用的基准数据temp的下标,同时相对排序
quickSort(arr, left, mid - 1); //将数组分为左半边,不需要包括mid是因为mid的位置已经是“绝对有序”的了
quickSort(arr, mid + 1, right); //将数据分为右半边
}
}
//main方法
public static void main(String[] args) {
QuickSort qs = new QuickSort();
Random ra = new Random();
int Max_Size = 10;
int Max_Num = 50;
int[] arr = new int[Max_Size];
for(int i = 0;i<arr.length;i++) { //随机数赋值
arr[i]=ra.nextInt(Max_Num+1);
}
System.out.println("随机产生的长度为"+Max_Size+"最大数值为"+Max_Num+"的数组原序为:" +"\n"+ Arrays.toString(arr));
qs.quickSort(arr, 0, arr.length - 1);
System.out.println("归并排序后的数组升序为:" +"\n"+ Arrays.toString(arr));
}
}
实现
5.归并排序
实现思路:递归mergesort方法用来将数组不断分割,分割到只剩下单个元素时,回溯,调用merge方法将两个相对有序的数组进行排序。
- merge方法:用来对各自有序的两个"数组"(其实还是在同一个数组中)进行合并(并),合并时让一个临时的新数组来接收(新的临时数组也要保证有序)在把新数组返回给原数组。(合并具体操作见代码)
- mergesort方法:将一个数组不断对半分段,分到只剩下单个元素为止。(利用递归来达成),当分到底时,递归结束。往上回溯。调用merge方法对有序的一段一段的"数组"合并同时排序。
核心代码块
public class MergeSort {
//这个方法用来对数组分段。通过递归实现
public void mergesort(int[] arr, int left, int right) {
if (left == right) //递归需要条件跳出,当数组被分到只剩自己时,跳出。
return; //void型 可以用return;跳出 返回空。return后面的语句都不会执行。
int mid = (left + right) / 2; //给一个中点
mergesort(arr, left, mid); //利用递归,当给出一个数组时不断调用自己(8分4,4分2,2分1) 把给出的数组分为左半段,从left到mid
mergesort(arr, mid + 1, right); //把给出的数组分为左半段,从mid+1到right
merge(arr, left, mid, right); //调用merge方法合并 排序。
}
//这个方法用来合并数组 并排序。
public void merge(int[] arr, int left, int mid, int right) { //right表示数组的右边边界下标
int[] temp = new int[right - left + 1]; //定义一个temp临时数组,长度不能是arr.length 因为传进来的数组一直都是那个数组。只是上下限变了
int i = 0; //用来当temp下标
int lp = left; // lp表示左半边数组的下标
int rp = mid + 1; // rp表示右半边数组的下标
//两个数组的最左(小)进行比较,小的那个传给temp.
while (lp <= mid && rp <= right) { //跳出条件,当左半边和右半边同时大于界线时跳出
temp[i++] = arr[lp] < arr[rp] ? arr[lp++] : arr[rp++]; //三元运算符 lp++都是它本身运行完后加
}
//以下两个while只会执行一个,用于把剩下的元素依次传给temp
while (lp <= mid) { //若是不运行 证明lp下标已经越界了
temp[i++] = arr[lp++];
}
while (rp <= right) {
temp[i++] = arr[rp++];
}
//把temp在返回给arr原数组。
for (int j = 0; j < temp.length; j++) { //不能用arr.length 一样的道理,长度一致都没变
arr[left + j] = temp[j]; //加上left的原因也是一样,left是某段"数组"的开头
}
}
//main接口,调用方法实现
public static void main(String[] args) {
MergeSort ms = new MergeSort();
int arr[] = { 16, 21, 4, 8, 0, 6, 1, 5};
System.out.println("原数组排序为:" + Arrays.toString(arr));
ms.mergesort(arr, 0, arr.length - 1);
System.out.println("归并排序后的数组升序为:" + Arrays.toString(arr));
}
}
实现
后话
常用的几种排序,还有3,4个没写。周末或者什么时候有时间,在研究下,下次补上。