文章目录
1.稳定性
相同的两个数据,经过排序后,其相对位置没有发生改变,我们就称该排序算法具有稳定性。
2.插入排序
插入排序的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
2.1图解过程
2.2代码实现
import java.util.Arrays;
public class Test0613_1 {
//9,5,7,2,3,6,8
public static void insertSort(int[] arr){
int bound=1; //待插入元素的下标
for(;bound<arr.length;bound++){ //控制插入排序的次数
int temp=arr[bound]; //把待插入的值放到临时变量中
int cur=bound-1;
for(;cur>=0;cur--){ //循环比较,插入合适的位置
if(arr[cur]>temp){
arr[cur+1]=arr[cur]; //不符合升序,元素往后移
}else {
break; //找到合适位置了,跳出整个循环
}
}
arr[cur+1]=temp;//循环完后,待插入的元素要放到合适的位置
}
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
insertSort(arr);
System.out.println("插入排序后:"+"==>"+"升序");
System.out.println(Arrays.toString(arr));
}
}
运行结果:
2.3性能分析
3.希尔排序
希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。(分组插排!!)
3.1图解过程
3.2代码实现
import java.util.Arrays;
public class Test0613_2 {
public static void ShellSort(int[] arr){
int gap=arr.length/2;
while (gap>=1) { //分组系数,直到1为止就成插入排序了
int bound = gap; //从分组系数位置出发
for (; bound < arr.length; bound++) { //控制插排的次数
int temp = arr[bound];
int cur = bound - gap;
for (; cur >= 0; cur -= gap) { //控制每次插排元素要放到的位置
if (arr[cur] > temp) {
arr[cur + gap] = arr[cur]; //不符合排序要求,元素往后移动
} else {
break; //找到合适的位置了
}
}
arr[cur + gap] = temp; //内层循环,每次插排元素要放的位置
}
gap=gap/2; //分组系数每次除2,直到为1
}
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
ShellSort(arr);
System.out.println("希尔排序后:"+"==>"+"升序");
System.out.println(Arrays.toString(arr));
}
}
运行结果:
3.3性能分析
4.选择排序
每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完 。
4.1图解过程
4.2代码实现
import java.util.Arrays;
public class Test0613_3 {
public static void SlecteSort(int[] arr){
for(int bound=0;bound<arr.length;bound++){ //控制打擂台的次数
for(int j=bound+1;j<arr.length;j++){ //和数组里其他元素一次比较
if(arr[bound]>arr[j]){
int temp=arr[bound];
arr[bound]=arr[j];
arr[j]=temp;
}
}
}
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
SlecteSort(arr);
System.out.println("选择排序后:"+"==>"+"升序");
System.out.println(Arrays.toString(arr));
}
}
运行结果:
4.3性能分析
5.堆排序
基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。(通过堆的性质完成排序)
5.1图解过程
5.2代码实现
import java.util.Arrays;
public class Test0613_4 {
public static void HeapSort(int[] arr){
//1.先建堆(大堆)
for(int i=(arr.length-1-1)/2;i>=0;i--){
ShiftDown(arr,arr.length,i);
}
//大堆建成后,拿堆顶元素和最后一个元素交换,然后最后一个元素出堆,再向下调整堆
int heapsize=arr.length; //一开始堆的大小就为数组的大小
for(int i=0;i<arr.length;i++){
//交换第一个堆顶元素和最后一个元素
int temp=arr[0];
arr[0]=arr[heapsize-1];
arr[heapsize-1]=temp;
//最后一个元素要出堆
heapsize--;
//向下调整堆
ShiftDown(arr,heapsize,0);
}
}
public static void ShiftDown(int[] arr,int size,int index){
int parent=index;
int child=2*parent+1; //左孩子
while (child<size){ //左孩子节点小于堆的大小即可入堆调整
//选出左右孩子中大的一个
if (child + 1 < size && arr[child] <arr[child+1]) {
child=child+1;
}
//父节点的值小于孩子节点的值交换
if(arr[parent]<arr[child]){
int temp=arr[parent];
arr[parent]=arr[child];
arr[child]=temp;
}else {
break; //调整好了跳出循环
}
parent=child; //继续往下调整
child=2*parent+1;
}
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
HeapSort(arr);
System.out.println("堆排序排序后:"+"==>"+"升序");
System.out.println(Arrays.toString(arr));
}
}
运行结果:
5.3性能分析
6.冒泡排序
冒泡排序可以参考这个链接有详细介绍:https://blog.csdn.net/m0_54798309/article/details/112990346?utm_source=app&app_version=4.5.4
7.快速排序
从待排序区间选择一个数,作为基准值(pivot);Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;然后对左右区间重复这样的操作,直到区间长度为1就代表有序了。
7.1图解过程
7.2代码实现(递归版本)
import java.util.Arrays;
public class Test0613_5 {
public static void QuickSort(int[] arr){
_QuickSort(arr,0,arr.length-1);
}
public static void _QuickSort(int[] arr,int left, int right){
if(left>=right){
return;
}
int index=partition(arr,left,right);
//递归左边快排
_QuickSort(arr,left,index-1);
//递归右边快排
_QuickSort(arr,index+1,right);
}
public static int partition(int[] arr,int left,int right){
int l=left;
int r=right;
int var=arr[right]; //基准元素
while (l<r){
//若选取右边元素作为基准值,就先从左边出发。
//从左边出发寻找一个比基准值大的元素
while (l<r && arr[l]<=var){
l++;
}
//从右边出发选择一个比基准值小的元素
while (l<r && arr[r]>=var){
r--;
}
//从左边和右边找到合适的元素后,进行交换
int temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
}
//循环结束后,将基准值和左右指针相交处交换
int temp=arr[l];
arr[l]=arr[right];
arr[right]=temp;
return l; //返回左右指针相交点
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
QuickSort(arr);
System.out.println("快速排序排序后:"+"==>"+"升序");
System.out.println(Arrays.toString(arr));
}
}
运行结果:
7.3代码实现(非递归版本)
import java.util.Arrays;
import java.util.Stack;
public class Test0613_6 {
public static void QuickSortByloop(int[] arr){
Stack<Integer> stack=new Stack<>();
stack.push(0);
stack.push(arr.length-1);
while (!stack.isEmpty()){
int right=stack.pop();
int left=stack.pop();
if(left>=right){
continue; //空区间或一个一个元素,就不要排序
}
int index=partition(arr,left,right);
// 右侧区间: [index + 1, right]
stack.push(index + 1);
stack.push(right);
// 左侧区间: [left, index - 1]
stack.push(left);
stack.push(index - 1);
}
}
public static int partition(int[] arr,int left,int right){
int l=left;
int r=right;
int var=arr[right]; //基准元素
while (l<r){
//若选取右边元素作为基准值,就先从左边出发。
//从左边出发寻找一个比基准值大的元素
while (l<r && arr[l]<=var){
l++;
}
//从右边出发选择一个比基准值小的元素
while (l<r && arr[r]>=var){
r--;
}
//从左边和右边找到合适的元素后,进行交换
int temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
}
//循环结束后,将基准值和左右指针相交处交换
int temp=arr[l];
arr[l]=arr[right];
arr[right]=temp;
return l; //返回左右指针相交点
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
QuickSortByloop(arr);
System.out.println("快速排序排序后:"+"==>"+"升序");
System.out.println(Arrays.toString(arr));
}
}
运行结果:
7.4性能分析(递归版本)
8.归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
8.1图解过程
8.2代码实现(递归版本)
import java.util.Arrays;
public class Test0614_6 {
public static void mergeSort(int[] arr){
_mergeSort(arr,0,arr.length);
}
public static void _mergeSort(int[] arr, int left, int right) {
if(right-left<=1){ //区间长度为1了就不需要再切分了
return;
}
int mid=(left+right)/2;
//左边区间变成有序
_mergeSort(arr,left,mid);
//右边区间变成有序
_mergeSort(arr,mid,right);
//合并左右区间
merge(arr,left,mid,right);
}
public static void merge(int[] arr,int left,int mid,int right){
if(left>=right){
return; //空的区间不需要合并
}
int[] temp=new int[right-left];
int indextep=0;
int cur1=left;
int cur2=mid;
while (cur1<mid && cur2<right){
if(arr[cur1]<=arr[cur2]){
temp[indextep]=arr[cur1];
indextep++;
cur1++;
}else {
temp[indextep]=arr[cur2];
indextep++;
cur2++;
}
}
//左边区间有剩余,直接拷贝去零时数组
while (cur1<mid){
temp[indextep]=arr[cur1];
indextep++;
cur1++;
}
//若右边区间有剩余,则拷贝去数组
while (cur2<right){
temp[indextep]=arr[cur2];
indextep++;
cur2++;
}
//拷贝回原来的数组
for(int i=0;i<temp.length;i++){
arr[left+i]=temp[i];
}
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
System.out.println("归并排序排序后:"+"==>"+"升序");
mergeSort(arr);
System.out.println(Arrays.toString(arr));
}
}
运行结果:
8.3代码实现(非递归版本)
import java.util.Arrays;
public class Test0614_7 {
public static void merge(int[] arr,int left,int mid,int right){
if(left>=right){
return; //空的区间不需要合并
}
int[] temp=new int[right-left];
int indextep=0;
int cur1=left;
int cur2=mid;
while (cur1<mid && cur2<right){
if(arr[cur1]<=arr[cur2]){
temp[indextep]=arr[cur1];
indextep++;
cur1++;
}else {
temp[indextep]=arr[cur2];
indextep++;
cur2++;
}
}
//左边区间有剩余,直接拷贝去零时数组
while (cur1<mid){
temp[indextep]=arr[cur1];
indextep++;
cur1++;
}
//若右边区间有剩余,则拷贝去数组
while (cur2<right){
temp[indextep]=arr[cur2];
indextep++;
cur2++;
}
//拷贝回原来的数组
for(int i=0;i<temp.length;i++){
arr[left+i]=temp[i];
}
}
public static void mergeSortByloop(int[] arr){
int gap=1;
for(;gap<arr.length;gap*=2){
for(int i=0;i<arr.length;i+=2*gap){
int left = i;
int mid = i + gap;
if (mid >= arr.length) { //防止数组下标越界
mid = arr.length;
}
int right = i + 2 * gap;
if (right >= arr.length) {
right = arr.length;
}
merge(arr, left, mid, right);
}
}
}
public static void main(String[] args) {
int[] arr={9,5,7,2,3,6,8};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
System.out.println("归并排序排序后:"+"==>"+"升序");
mergeSortByloop(arr);
System.out.println(Arrays.toString(arr));
}
}
运行结果: