这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战”
上一篇说到了数据结构与算法中的基础排序和冒泡排序。今天这篇文章主要内容:
- 快速排序
- 插入排序
- 选择排序
- 希尔排序
- 归并排序
快速排序
1. 介绍
快速排序是对冒泡排序的一种改进。通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分所有的数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
2. 示意图
3. 代码实现
/**
* author:韩国庆
* date:2021/3/9 16:53
* version:1.0
*/
public class QuickSort {
public static void main(String[] args) {
int[] arrays = new int[]{2,9,4,7,3,1,6,5};
sort(arrays,0,arrays.length-1);
System.out.println(Arrays.toString(arrays));
}
public static void sort(int[] arrays,int left,int right){
int l = left;//左下标
int r = right;//右下标
int pivot = arrays[(left+right)/2];//中间值
int temp = 0;
/**
* 循环的目的是让比pivot小的值放在左边,比pivot大的值放在右边
*/
while (l<r){
//在pivot左边找到大于等于pivot值,再退出
while (arrays[l]<pivot){
l+=1;
}
/**
* 在pivot右边找小于等于pivot值,再退出
*/
while (arrays[r]>pivot){
r-=1;
}
/**
* 如果 l>=r说明左边全部是小于pivot的值,右边全部是大于pivot的值
*/
if (l>=r){
break;
}
/**
* 交换位置
*/
temp = arrays[l];
arrays[l] = arrays[r];
arrays[r] = temp;
/**
* 交换后发现arrays[l] == piovt值,则r--;
*/
if (arrays[l]==pivot){
r-=1;
}
/**
* 交换后发现arrays[r] == piovt值,则l++;
*/
if (arrays[r] == pivot){
l+=1;
}
/**
* 如果l==r 必须l++,r--,否则出现溢栈
*/
if (l==r){
l+=1;
r-=1;
}
if (left<r){
sort(arrays,left,r);
}
if (right>l){
sort(arrays,l,right);
}
}
}
}
插入排序
1. 介绍
插入排序属于内部排序,是对于排序的元素以插入的方式寻找该元素的适当位置,已达到排序的目的。
2. 示意图
3. 代码实现
/**
* author:韩国庆
* date:2021/3/12 14:44
* version:1.0
*/
public class InsertSort {
public static void main(String[] args) {
int[] arrays = new int[]{2,6,4,1,3,7,5};
sort(arrays);
System.out.println(Arrays.toString(arrays));
}
public static void sort(int[] arrays){
int[] arr = arrays;
int temp;
for (int i=1;i<arr.length;i++){
System.out.println("第 "+i+" 次");
for (int j=i;j>=1;j--){
if (arr[j]<arr[j-1]){
temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
}else {
break;
}
}
}
}
}
选择排序
1. 介绍
选择排序也属于内部排序法,是从欲排序的数据中按指定的规则选择某一个元素,再以规则交换位置后达到的排序目的。
它的工作原理是:
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
2. 示意图
3.源码实现
/**
* author:韩国庆
* date:2021/3/12 15:02
* version:1.0
*/
public class SelectSort {
public static void main(String[] args) {
int[] arrays = new int[]{2,6,4,1,3,7,5};
sort(arrays);
System.out.println(Arrays.toString(arrays));
}
public static void sort(int[] arrays){
for (int i=0;i<arrays.length;i++){
System.out.println(" "+i);
int index = i;
for (int j=arrays.length-1;j>i;j--){
if (arrays[j]<arrays[index]){
index = j;
int temp = 0;
temp = arrays[j];
arrays[j] = arrays[i];
arrays[i] = temp;
}
}
}
}
}
希尔排序
1. 介绍
希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
2. 示意图:
3. 源码实现
/**
* author:韩国庆
* date:2021/3/13 15:12
* version:1.0
*/
public class ShellSort {
public static void main(String[] args) {
int[] array = {7,3,2,5,9,4,8,1,6};
// shellSort(array); //交换法
shellSort2(array);//移动法
}
/**
* 交换方式
* @param arrays
*/
public static void shellSort(int[] arrays){
int temp = 0;
int count = 0;
for (int gap = arrays.length/2;gap>0;gap/=2){
for (int i=gap;i<arrays.length;i++){
for (int j=i-gap;j>=0;j-=gap){
if (arrays[j]>arrays[j+gap]){
temp=arrays[j];
arrays[j] = arrays[j+gap];
arrays[j+gap] = temp;
}
}
}
System.out.println("第"+(++count)+"轮 = "+ Arrays.toString(arrays));
}
}
/**
* 移位法
*/
public static void shellSort2(int[] arrays){
for (int gap=arrays.length/2;gap>0;gap/=2){
for (int i=gap;i<arrays.length;i++){
int j=i;
int temp = arrays[j];
if (arrays[j]<arrays[j-gap]){
while (j-gap>=0 && temp<arrays[j-gap]){
//移动
arrays[j] = arrays[j-gap];
j-=gap;
}
arrays[j] = temp;
}
}
}
System.out.println(Arrays.toString(arrays));
}
}
归并排序
1. 介绍
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
2. 示意图
我们需要将两个已经有序的子序列合并成一个有序序列,比如上图最后一次合并,将[2,4,5,6]和[1,3,7,8]已经有序的子序列合并最终序列[1,2,3,4,5,6,7,8]
3. 源码实现
/**
* author:韩国庆
* date:2021/3/15 14:29
* version:1.0
*/
public class MergetSort {
public static void main(String[] args) {
int[] arrays = {8,4,7,2,3,6,1,5};
/**
* 定义一个临时数组
*/
int[] temp = new int[arrays.length];
mSort(arrays,0,arrays.length-1,temp);
System.out.println(Arrays.toString(arrays));
}
public static void mSort(int[] array,int left,int right,int[] temp){
if (left<right){
int mid = (left+right)/2;
/**
* 向左进行分解
*/
mSort(array,left,mid,temp);
/**
* 向右分解
*/
mSort(array,mid+1,right,temp);
/**
* 合并
*/
sort(array,left,right,mid,temp);
}
}
public static void sort(int[] arrays,int left,int right,int mid,int[] temp){
/**
* 初始化i,指向左边序列的初始索引值
*/
int i = left;
/**
* 初始化j,指向左边序列初始值
*/
int j = mid+1;
/**
* 初始化 t,指向数组的当前索引
*/
int t = 0;
/**
* 先把左右两边的数据按照有序序列方式填充到temp数组中
* 直至左右两边的有序序列,有一边处理完毕为止
*/
while (i<=mid && j<=right){
/**
* 如果左边的有序序列的当前元素小于等于右边有序序列的当前元素,即让左边的当前元素填充到temp数组中
然后 t++,i++
*/
if (arrays[i]<=arrays[j]){
temp[t] = arrays[i];
t+=1;
i+=1;
}else {
temp[t] = arrays[j];
t+=1;
j+=1;
}
}
/**
* 把剩余数据的一边的数据一次全部填充到temp;
*/
while (i<=mid){
temp[t] = arrays[i];
t+=1;
i+=1;
}
while (j<=right){
temp[t] = arrays[j];
t+=1;
j+=1;
}
/**
* 将temp数组中的元素拷贝至arrays数组中。这里不是每次拷贝所有的元素
*/
t=0;
int tempIndex = left;
while (tempIndex<=right){
arrays[tempIndex] = temp[t];
t+=1;
tempIndex +=1;
}
}
}