前言
八大排序算法:
直接插入排序、希尔排序、简单选择排序、堆排序、冒泡排序、快速排序、归并排序、基数排序
一、归并排序
1)基本介绍
2)基本思想
3)代码实现
public class MergeSort {
public static void main(String[] args) {
int arr[] = {8, 4, 5, 3, 2, 7, 6, 1};
int temp[] = new int[arr.length];
mergeSort(arr, 0, arr.length - 1, temp);
System.out.println(Arrays.toString(arr));
}
//分+合
public static void mergeSort(int[] arr,int left,int right,int[] temp){
if (left < right){
int mid = (left + right)/2;
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右递归分解
mergeSort(arr, mid + 1,right, temp);
//合并
merge(arr,left,mid,right,temp);
}
}
//合并的方法
/**
*
* @param arr 需要排序的数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边有序序列索引
* @param temp 中转数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left;
int j = mid + 1;
int t = 0;//中转数组的下标
//步骤1.
//把左右两边的有序序列数按规则填充到中转数组
//直到有一边序列都填完了
while (i <= mid && j <= right){//进行步骤1的条件
//左边的小于右边的,就将左边这个小的填到temp
//然后t,i后移
if(arr[i] < arr[j]){
temp[t] = arr[i];
t++;
i++;
}else {//否则右边这个小的数填到temp,然后t,j后移
temp[t] = arr[j];
t++;
j++;
}
}
//步骤2
//把有剩余的有序序列依次填到temp
while (i <= mid){//说明左边有剩余
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right){
temp[t] = arr[j];
t++;
j++;
}
//步骤3
//把temp复制到原来的数组arr
t = 0;
int tempLeft = left;
while (tempLeft <= right){
arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
}
二、冒泡排序
1)基本介绍
2)代码实现
public static void bubbleSort(int arr[]){
int temp = 0;
boolean flag = false;//标识符,判断是否进行过交换,用来让排序提前结束
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
flag = true;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
//System.out.println("第" + (i+1) + "趟排序后");
//System.out.println(Arrays.toString(arr));
if (!flag){
break;
}else {
flag = false;
}
}
}
三、选择排序
1)基本介绍
2)基本思想
3) 思路
4)代码实现
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;//假定最小值的索引
int min = arr[i];//假定一个最小值
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {//说明假定的最小值,并不是最小;若从大到小,则改成<
min = arr[j];//重置
minIndex = j;
}
}
//将最小值放在arr[0],即交换
if (minIndex != i) {//在原位置的不进行交换
arr[minIndex] = arr[i];
arr[i] = min;
}
//System.out.println("第" + (i + 1) + "轮交换");
//System.out.println(Arrays.toString(arr));
}
}
四、插入排序
1)基本介绍
2)思路图分析
3)代码实现
public static void insertSort(int[] arr){
for (int i = 0; i < arr.length; i++) {
//定义无序表里的那个待插入的数
int insertVal = arr[i];
int insertIndex = i - 1;//arr[i]的前面的数的下标,有序表里的数
//给insertVal找插入位置
while (insertIndex >= 0 && insertVal < arr[insertIndex]){
//insertVal < arr[insertIndex]说明不能插在这,还得往有序表前找
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
//当退出while后,说明位置找到,insertIndex+1
arr[insertIndex + 1] = insertVal;
System.out.println("第" + i + "轮插入");
System.out.println(Arrays.toString(arr));
}
}
五、希尔排序
1)基本介绍
2)思路分析图
4)代码实现,希尔排序可分为交换法和移动法
//交换
public static void shellSort01(int[] arr){
int temp = 0;
int count = 0;
//分组
for (int gap = arr.length / 2; gap > 0; gap /= 2){
for (int i = gap; i < arr.length; i++){
//遍历各组中所有的元素,本例子共5组,每组两个元素
//步长为5,即十个数分成五组,每组中的两个元素相隔5个步数
for (int j = i - gap; j >= 0; j -= gap){
//如果当前元素大于同组中的另一个元素,则交换
if (arr[j] > arr[j + gap]){
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
System.out.println("希尔排序第" + (++count) + "轮后" + Arrays.toString(arr));
}
}
//移动,快得多
public static void shellSort02(int[] arr){
for (int gap = arr.length / 2; gap > 0; gap /= 2){
//从第gap个元素,逐个对其所在的组进行直接插入排序
for (int i = gap; i < arr.length; i++){
int j = i;
int temp = arr[j];
if (arr[j] < arr[j - gap]){
while (j - gap >= 0 && temp < arr[j - gap]){
//移动
arr[j] = arr[j - gap];
j -= gap;
}
//退出while循环,找到temp插入的位置
arr[j] = temp;
}
}
}
}
六、快速排序
1)基本介绍
2)思路图分析
3)代码实现
public static void quickShort(int[] arr,int left,int right){
int l = left;//左下标
int r = right;//右下标
int pivot = arr[(left + right)/2];//中值
int temp = 0;
//while 让大于pivot到右边,小于到左边
while (l < r){
//在pivot的左边找到大于等于pivot的值,退出
while (arr[l] < pivot){
l += 1;
}
//在pivot的右边找到小于等于pivot的值,退出
while (arr[r] > pivot){
r -= 1;
}
//如果l>=r,说明排好了
if (l >= r){
break;
}
//交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//如果交换后,arr[l]==pivot,则r--,前移
if (arr[l] == pivot){
r--;
}
//如果交换后,arr[r]==pivot,则l++,后移
if (arr[r] == pivot){
l++;
}
}
//如果l==r,必须l++,r--,否则栈溢出
if (l == r){
l += 1;
r -= 1;
}
//向左递归
if (left < r){
quickShort(arr,left,r);
}
//向右递归
if (right > l){
quickShort(arr,l,right);
}
}
七、基数排序
1)基本介绍
2)基本思想
3)思路分析图,以下图中的arr为例,需三轮排序
第一轮排序,定义一个二位数组,表示十个桶。先按个位,将每个元素放到对应的桶(一维数组)中,比如53的个位是3,就放到下标为3的桶中,然后按桶的顺序,桶中元素的顺序,将各元素依次放回到原来数组中
第二轮 ,按十位,将每个元素放到对应的桶(一维数组)中,比如53的十位是5,就放到下标为5的桶中,如果元素是4,十位就补0,放到下标为0的桶中,然后按桶的顺序,桶中元素的顺序,将各元素依次放回到原来数组中
第三轮,按百位,同上两轮。
4)代码实现
public static void radixSort(int arr[]){
//1.得到数组中最大数的位数
int max = arr[0];
for (int i = 1; i < arr.length; i++){
if (arr[i] > max){
max = arr[i];
}
}
//得到最大数是几位数
int maxLength = (max + " ").length();
//定义一个二维数组,表示十个桶,每个桶就是一个一维数组
//每个桶(一维数组)的大小定位arr.length,防止数据溢出,空间换时间
int[][] bucket = new int[10][arr.length];
//定义一个一维数组来记录各个桶的每次放入数据的个数
//bucketElementCounts[0],记录的就是bucket[0]桶的放入数据的个数
int[] bucketElementCounts = new int[10];
for (int i = 0, n = 1; i < maxLength; i++, n *= 10){
//每个元素的位数进行排序,个,十,百,n代表位数
for (int j = 0; j < arr.length; j++){
//1.取出每个元素的对应位数
int individual = arr[j] / n % 10;
//2.放入到对应的桶
bucket[individual][bucketElementCounts[individual]] = arr[j];
bucketElementCounts[individual]++;
}
//3.将桶中的数据放到原数组
//按照桶的顺序(一维数组的下标)依次取出数据,放到原来数组
int index = 0;
//遍历每个桶,取出数据放到原来数组
for (int k = 0; k < bucketElementCounts.length; k++){
//判断桶里有没有数据
if (bucketElementCounts[k] != 0){
//这第k个桶有数据,全取出来,放arr里
for (int l = 0; l < bucketElementCounts[k]; l++){
arr[index++] = bucket[k][l];
}
}
//第i+1轮后,桶要清零
bucketElementCounts[k] = 0;
}
System.out.println("第"+(i+1)+"轮排序后,arr=" + Arrays.toString(arr));
}
}