常用排序算法总结

排序算法

首先

排序算法虽然说是很基础的算法但是在找实习的时候经常被问,让你当场就要写出来。虽然简单但是还是很容易忘掉,现在就把这个常用到的排序算法做一个总结。

冒泡排序
思路

在这里插入图片描述
小结:
1、一共要进行 (nums.length - 1) 次
2、每一趟排序的次数在逐渐减少
3、如果我们发现在某趟排序中,没有发生一次交换那么就直接提前结束冒泡排序,这就是优化算法

代码实现

冒泡排序的时间复杂度分析:因为需要进行两次的for循环遍历所以时间复杂度为O(n*n) 即 O(n2)。

	public class Main{
		public static void main(String[] args){
			int[] nums = {3,9,-1,10,-2};
			//设置一个临时变量
			int temp = 0;
			for(int i = 0; i < nums.length - 1; i ++){
				for(int j = 0; j < nums.length -1 - i; j++){
					if(nums[j] > nums[j+1]){
						temp = nums[j];
						nums[j] = nums[j+1];
						nums[j+1] = temp;
					}
				}
				//把每一层的打印出来
				System.out.println(Arrays.toString(nums));
			}
		}
	}
对冒泡排序进行优化
	public class Main{
		public static void main(String[] args){
			int[] nums = {3,9,-1,10,-2};
			//设置一个临时变量
			int temp = 0;
			boolean flag = false;//表示变量,表示是否进行了交换
			for(int i = 0; i < nums.length - 1; i ++){
				for(int j = 0; j < nums.length -1 - i; j++){
					if(nums[j] > nums[j+1]){
						flag = true;
						temp = nums[j];
						nums[j] = nums[j+1];
						nums[j+1] = temp;
					}
				}
				//把每一层的打印出来
				System.out.println(Arrays.toString(nums));
				if(!flag){ //在一趟排序中一次交换都没有发生
					break;
				}else{//重置flag!!!,进行下一次判断
					flag = false;
				}
			}
		}
	}
选择排序
思路在这里插入图片描述
图解过程

在这里插入图片描述

代码实现

选择排序的时间复杂度分析:选择排序需要进行两次的for循环遍历,所以时间复杂度为 O(n*n) 即 O(n2)。

	public calss Main{
		public static void main(String[] args){
			int[] nums = {34,1,119,101};
			
			for(int i = 0; i < nums.length - 1; i++){
				//假定第一个数就是最小值
				int min = nums[i]; 
				int minIndex = i;
				for(int j = i + 1; j < nums.length; j++){
					//按从大到小的顺序排,如果说找到的数会比刚刚定义最前面的
					//数更小的时候那么就将最小值及其下标进行一个重置
					if(min > nums[j]){
						min = nums[j];
						minIndex = j;
					}
				}
				//做完一轮之后那么就开始交换了
				//说明:如果说一开始定义的最小值还是这个小标那么就说明没有找到最小值,
				//即最小值就是其本身,所以无需交换
				if(minIndex != i){
					nums[minIndex] = nums[i];
					nums[i] = min;
				}
			}
			System.out.println(Arrays.toString(nums));
		}
	}
插入排序
思路

在这里插入图片描述

代码实现

插入排序的时间复杂度分析:插入排序需要执行一个for循环和一个while循环,其时间复杂度为O(n*n), 即O(n2)。

	public class Main{
		public static void main(String[] args){
			int[] nums = {101,34,119,111};

			for(int i = 1; i < nums.length; i++){
				int insertVal = arr[i]; //带插入的数
				int insertIndex = i - 1; //待插入数的前面一位数的小标
				
				//说明:
				//1、insertIndex >= 0 保证在给 insertVal 找插入位置,不越界
				//2、insertVal < nums[insertIndex] 待插入的数,还没有找到最终插入位置
				//3、需要将 nums[insertIndex] 后移一位
				while(insertIndex >= 0 && insertVal < nums[insertIndex]){
					nums[insertIndex + 1] = nums[insertIndex];
					insertIndex --;
				}
				//退出当前的循环那么久说明找到了最终待插入的位置,insertIndex + 1
				nums[inserrIndex + 1] = insertVal;
				
			}
			System.out.println(Arrays.toString(nums));
		}
	}
希尔排序Shell
思路

希尔排序是一个缩小增量排序 ,希尔排序就是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序,随着增量逐渐减少,每组包含的关键字越多,当增量减至1时,整个文件恰分成一组,算法便终止。

思路图解

在这里插入图片描述
在这里插入图片描述

代码实现

希尔排序的时间复杂度是 O(n3/2)。
1、交换法

	public calss Main{
		public class void main(String[] args){
			int[] nums = {8,3,4,9,6,2,7,1,0};
			int temp = 0;
			for(int gap = nums.length/2; gap > 0 ; gap /=2 ){
				for(int i = gap; i < nums.length; i ++){
					for(int j = i - gap; j >=0; j -= gap){
						if(nums[j] > nums[j + gap]){
							temp = nums[j];
							nums[j] = nums[j + gap];
							nums[j + gap] = temp;
						}
					}
				}
			}
			System.out.println(Arrays.toString(nums));
		}
	}

2、移动法(其实就是在中间加了一个插入排序的思想)

	public calss Main{
		public calss void main(String[] args){
		int[] nums = {7,2,5,4,8,0};
			for(int gap = nums.length; gap > 0; gap /= 2){
				for(int i = gap; i < nums.length; i++){
					int index = i;
					int temp = nums[i];
					if(nums[index] > nums[index - gap]){
						while(index - gap > 0 && temp < nums[index - gap]){
						nums[index] = nums[index - gap];
						index -= gap;
						}
						//退出while后找到最终的位置
						nums[index] = temp;
					}
				}
			}
		}
	}
快速排序 QuickSort
思路

在这里插入图片描述

代码实现

快速排序的时间复杂度为 O(nlogn)。

	public class Main{
		public static void main(Stroing[] args){
			int[] nums = {-9,78,0,23,-456,70};
			quickSort(nums,0,nums.length-1);
			System.out.println(Arrays.toString(nums));
		}
		public static void quickSort(int[] nums,int left, int right){
			int l = left;//左下标
			int r = right;//右下标
			//pivot中轴线
			int pivot = nums[(left + right)/2];
			int temp;//临时变量,交换的时候使用
			//while循环的目的是将比pivot大的数放到右边去,比pivot小的数放到左边去。
			while(l < r){
				//在pivot的左边一直找,找到大于等于pivot的值才退出
				while(nums[l] < pivot){
					l += 1;
				}
				//在pivot的右边一直找,找到小于等于pivot值,才退出
				while(nums[r] > pivot){
					r -= 1;
				}
				//如果l >= r 说明pivot的左右两边的值,己经按左边全部是小于pivot的值,右边全部是大于pivot的值
				if(l >= r){
					break;
				}
				//交换
				temp = nums[l];
				nums[l] = nums[r];
				nums[r] = temp;

				//如果交换完之后,发现这个nums[l] == pivot 值相等,r--,前移
				if(nums[l] == pivot){
					r -= 1;
				}
				//如果交换完之后,发现这个nums[r] == pivot 值相等,r--,前移
				if(nums[r] == pivot){
					l += 1;
				}
			}
			//如果 l == r 必须l ++,r--;否则会栈溢出
			if(l == r){
				l ++;
				r --;
			}
			//向右递归
			if(left < r){
				qucikSort(nums,left,r);
			}
			//向左di递归
			if(ringt > l ){
				qucikSort(nums,l,right);
			}
			
		}
	}
归并排序
思路在这里插入图片描述
步骤

在这里插入图片描述

代码实现

归并排序的时间复杂度分析:mergeSort()需要遍历n次,merge()方法需要logn 次,所以时间复杂度为 O(nlogn)。

	public class Merge {
    public static void main(String[] args) {
        int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
        //归并排序需要额外的空间
        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) {
        //左边的有序序列的初始索引,初始化i
        int i = left;
        //初始化j,右边有序序列的初始索引
        int j = mid + 1;
        //指向temp数组的当前索引
        int t = 0;

        //(1)
        //先把左右两边(有序)的数组按照规则填充到temp数组
        //知道左右两边的有序序列,有一边处理完毕为止
        while (i <= mid && j <= right) {
            if (arr[i] <= arr[j]) {
                temp[t] = arr[i];
                t++;
                i++;
            } else {
                temp[t] = arr[j];
                t++;
                j++;
            }
        }
        //(2)
        //把有剩余数据的一边的数据全部依次填充到temp
        while (i <= mid) {
            //左边的序列中还有剩余的元素,就全部填充到temp
            temp[t] = arr[i];
            t++;
            i++;
        }

        while (j <= right) {
            //说明右边还有剩余的元素,就全部填充到temp中去
            temp[t] = arr[j];
            t++;
            j++;
        }
        //(3)
        //将temp数组元素拷贝到arr
        //注意,并不是每次拷贝所有
        t = 0;
        int tempLeft = left;
        //System.out.println("tempLeft="+tempLeft+" right="+right);
        while (tempLeft <= right) {
            //第一次合并:tempLeft = 0,right = 1;
            //第二次合并:tempLeft = 2,right = 3;
            //....
            //最后一次合并:tempLeft = 0,right = 7;
            arr[tempLeft] = temp[t];
            t++;
            tempLeft++;
        }
    }
}
堆排序
思路

1)将无序序列构建成一个堆,根据升降序需求选择大顶堆(升序)或小顶堆(降序)
2)将堆顶元素与末尾元素交换,将最大元素“沉”到数组末端
3)重新调整结构,使其满足堆定义,然后继续交换堆顶的元素与当前末尾元素,反复执行调整+交换步骤,直到整个队列有序。

代码实现
	public class Heap {
    public static void main(String[] args) {
        int[] arr = {4,6,8,5,9};
        heapSort(arr);
    }

    public static void heapSort(int[] arr){
        int temp = 0;
        //1) 将无序序列构建成一个堆,根据升序降序的需求选择大顶堆或小顶堆
        for (int i = arr.length/2 -1; i >= 0; i--){
            adjustHeap(arr,i, arr.length);
        }

        /**
         * 2)将堆顶元素与末尾元素交换,将最大元素“沉”到数组末端
         * 3)重新调整结构,使其满足堆定义,然后继续交换堆顶的元素与当前末尾元素,反复执行调整+交换步骤,直到整个队列有序。
         */
        for (int j = arr.length - 1; j > 0; j--){
            //交换
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            adjustHeap(arr,0,j);
        }

        System.out.println("数组:"+ Arrays.toString(arr));
    }

    /**
     *
     * @param arr 待调整的数组
     * @param i 表示非叶子结点在数组中索引
     * @param length 表示对多少个元素继续调整,length 是在逐渐减少
     */
    public static void adjustHeap(int[] arr,int i , int length){
        //先取出当前元素的值,保存在临时变量
        int temp = arr[i];
        //1.k = 2 * i + 1 k是i结点的左子节点
        for (int k = 2 * i + 1; k < length; k = k * 2 + 1) {
            //说明左子结点的值小于右子节点
            if(k + 1 < length && arr[k] < arr[k + 1] ){
                k ++;
            }
            //如果子节点大于父结点
            if (arr[k] > temp){
                //把较大的值赋值给当前结点
                arr[i] = arr[k];
                //i指向k,继续循环比较
                i = k;
            }else{
                break;
            }
        }
        //当for循环结束后,我们已经将i为父结点的树的最大值放到了最顶部
        //将temp值放到调整后的位置
        arr[i] = temp;
    }
}

如果说还是对堆排序不清楚的建议去观看韩顺平的数据结构与算法的堆排序讲解,在108-110集!!!

最后

至此所有常见的排序算法都已经整理好啦,可以说基本上涵盖了面试中需要掌握的!收工~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Pareto排序算法是一种用于多目标优化问题的排序方法,它可以将解集中的解按照非支配关系进行排序。在Pareto排序算法中,首先需要确定一个基准解,然后将其他解与基准解进行比较,根据非支配关系将解分为不同的层次。具体的排序方法有很多种,包括庄家法、擂台赛法、递归方法以及快速排序方法等\[2\]。 快速排序方法是目前普遍使用的Pareto排序算法之一。它通过将解集划分为两个子集,然后对每个子集进行递归排序,最终将解集按照非支配关系进行排序。在快速排序方法中,首先选择一个解作为基准解,然后将其他解与基准解进行比较,将非支配的解放入一个新的集合中。接下来,对新集合进行递归排序,直到所有解都被排序为止\[2\]。 通过多轮排序,Pareto最优解集可以被找到。在排序的过程中,解集中的解按照非支配关系被分为不同的层次。最终,我们可以得到一个非支配层次关系的种群个体集合\[3\]。 总结来说,Pareto排序算法是一种用于多目标优化问题的排序方法,它可以将解集按照非支配关系进行排序。其中,快速排序方法是一种常用的Pareto排序算法,通过递归地将解集划分为子集并进行排序,最终得到Pareto最优解集\[2\]\[3\]。 #### 引用[.reference_title] - *1* *2* *3* [多目标进化算法(二)——非支配排序/NSGA-II](https://blog.csdn.net/qq_38537501/article/details/123360414)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聪明不喝牛奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值