🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客
🔥温馨提示:划到文末发现专栏彩蛋 点击这里直接传送
🔥本篇概览:详细讲解了排序简单篇——冒泡排序、选择排序、插入排序、希尔排序、快速排序全解析【附完整源码】。🌈⭕🔥
【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】
🌈序言:
排序算法千万不要爆冷!
🌈引出:
🌈1.选择排序
🔥核心思想
设置数组开始的为最小值下标,在后面完全遍历寻找最小值for(int i=0;i<n-1;i++),与开始的值交换位置,每次遍历都会将当前剩下的元素的最小值放在数组最前方排好序,再一次遍历再从当前排好序的数组末端for(int j=i+1;j<n;j++)出发寻求最值就好。
🔥代码
public static void selectionSort(int[] nums){
int len= nums.length;
for (int i = 0; i < len-1; i++) {
int minIndex=i;
for (int j = i; j < len; j++) {
if (nums[j]<nums[i]){
minIndex=j;
}
}
exch(nums,i,minIndex);
}
}
🌈2.冒泡排序
🔥核心思想
沿着数组从头到尾挨个比较,大的就往后面交换,这样每一次交换都会在队尾得到当前最大元素。
所以有双重for,第一重遍历全部元素-1,第二重遍历已经全部元素-1-i(已经排序好了的i个就不需要排序了。)
🔥小细节
len-1 按理说是需要排序len-1次的。因为当len-1都拍好了,第一个一定是最小的。所以是len-1.
boolean flag 这里使用flag来标记这样的事件。具体来说就是如果一开始或者中途就排序好了,就可以直接退出了,如果产生交换,说明还没排序好,如果没交换了,说明直接排序好了。直接退出。
🔥代码
public class BubbleSort {
public static int[] bubbleSort(int[] nums) {
int len=nums.length;
boolean flag;
// 这里排序比长度减一,因为其他的所有排好了,剩下的一定排好了。
for (int i = 0; i < len-1; i++) {
flag=false;
for (int j = 0; j < len - i - 1; j++) {
if (nums[j]>nums[j+1]){
nums[j]^=nums[j+1];
nums[j+1]^=nums[j];
nums[j]^=nums[j+1];
flag= true;
}
}
if (!flag){
break;
}
}
return nums;
}
}
结果
🌈3.插入排序:
🔥核心思想:
抽离出当前比较元素设为key,在前面找到合适位置index并插入。如果前面元素比他小,就将元素向后移(反正我刚才抽离来了一个位置),直至最后插入合适位置。
🔥细节:
1.int key=nums[i]; 抽离当前元素
2.nums[index+1]=nums[Index]; 当前元素向后移
3.nums[Index+1]=key 插入当前元素
public static void insertSort(int[] nums) {
int len= nums.length;
for (int i = 1; i < len; i++) {
int key= nums[i];
int Index=i-1;
while (Index>=0&&nums[Index]>key){
nums[Index+1]=nums[Index];
Index--;
}
nums[Index+1]=key;
}
}
🌈4.希尔排序:
🔥核心思想:
是插入排序的升级版抽离出当前比较元素设为key,在前面找到合适位置index并插入。如果前面元素比他小,就将元素向后移(反正我刚才抽离来了一个位置),直至最后插入合适位置。
记住插入排序就记住了希尔排序
🔥细节:
1.for (int gap = n/2; gap >0; gap/=2) ; 每次细化当前插入的间隔
2. for (int i = gap; i < n; i++); 表示这是0之后的当前间隔的第一个元素
3. int key=nums[i]; 抽离当前元素
4.nums[Index+gap]=nums[Index]; 将小于当前元素向后移动一个基本(gap)单元
5. nums[Index+gap]=key; 插入当前元素到正确的位置
public static void shellSort(int[] nums) {
int n=nums.length;
for (int gap = n/2; gap >0; gap/=2) {
for (int i = gap; i < n; i++) {
int key=nums[i];
int Index=i-gap;
// 对每个子数组进行插入排序
while (Index>=0&& nums[Index]>key){
nums[Index+gap]=nums[Index];
Index-=gap;
}
nums[Index+gap]=key;
}
}
}
🌈5.快速排序:
🔥递归思想:
随便找一个基数(一般就拿第一个),将整个数组中,小于它的数放在左边,大于它的数放在右边,这样会分成两个区间。再分别对这两个区间进行处理,最后即可得到的是排好序的数组。
🔥细节:
1.exch(a, lo, j); 注意再返回基准元素的新位置时,要与交换j处的元素交换位置,因为这才是基准位置该处于的位置。他的右边的j+1元素一定比他大,左边的一定比它小(实际上j位置处就比他小了)。
2.return j; 最后一定是返回该基准元素的位置方便左右区间分别再次快速排序。
3.大师级别代码
while ((a[++i] < a[lo])) {// 找出大于基准元素a[lo]的元素a[++i];
if (i == hi) break;
}
while (a[lo] > a[--j]) { // 找出小于基准元素a[lo]的元素a[--j];
if (j == lo) break;
}
public static void qiuckSort(int[] a) {
sort(a, 0, a.length - 1);
}
private static void sort(int[] a, int lo, int hi) {
if (hi <= lo) return;
int j = partition(a, lo, hi); // Partition the array
sort(a, lo, j - 1); // Sort the left part
sort(a, j + 1, hi); // Sort the right part
}
private static int partition(int[] a, int lo, int hi) {
int i = lo, j = hi + 1;
while (true) {
while (a[++i] < a[lo]) {// 找出大于基准元素a[lo]的元素a[++i];
if (i == hi) break;
}
while (a[lo] > a[--j]) { // 找出小于基准元素a[lo]的元素a[--j];
if (j == lo) break;
}
if (i >= j) break; // 出现这种情况说明已经拍好序了,左边一定比他小,右边一定比他大。直接退出就是.
// 交换 i 和 j 处的元素,确保左边部分的元素小于基准元素,右边部分的元素大于基准元素。
exch(a, i, j);
}
exch(a, lo, j);
return j;
}
private static void exch(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
🔥所有源码,一键测试:
package com.itheima.Array.sort;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
/**
* @Author: Ethan Yankang
* @Program: code-random-recordings
* @Date: 2024-08-06 13:01
**/
class sort {
//======================================================================
// 冒泡排序
public static void bubbleSort(int[] nums) {
int len = nums.length;
boolean flag;
// 这里排序比长度减一,因为其他的所有排好了,剩下的一定排好了。
for (int i = 0; i < len - 1; i++) {
flag = false;
for (int j = 0; j < len - i - 1; j++) {
if (nums[j] > nums[j + 1]) {
nums[j] ^= nums[j + 1];
nums[j + 1] ^= nums[j];
nums[j] ^= nums[j + 1];
flag = true;
}
}
if (!flag) {
break;
}
}
}
//======================================================================
// 快速排序
public static void qiuckSort(int[] a) {
sort(a, 0, a.length - 1);
}
// 递归思想,你排好了,左右在拍好了,就完全拍好了。
private static void sort(int[] a, int lo, int hi) {
if (hi <= lo) return;
int j = partition(a, lo, hi); // Partition the array
sort(a, lo, j - 1); // Sort the left part
sort(a, j + 1, hi); // Sort the right part
}
private static int partition(int[] a, int lo, int hi) {
int i = lo, j = hi + 1;
while (true) {
// 找出大于基准元素a[lo]的元素a[++i];
while ((a[++i]<a[lo])) {
if (i == hi) break;
}
// 找出小于基准元素a[lo]的元素a[--j];
while (a[lo]<a[--j]) {
if (j == lo) break;
}
// 出现这种情况说明已经拍好序了,左边一定比他小,右边一定比他大。直接退出就是。
if (i >= j) break;
// 交换找到的不合理元素位置。到最后肯定全部交换完了。
// 交换 i 和 j 处的元素,确保左边部分的元素小于基准元素,右边部分的元素大于基准元素。
exch(a, i, j);
}
// 这里是抽离基准元素的动作,将他抽离到刚刚让左边比他小,右边比他大的位置上去。为什么一定是这样呢?
// 因为j+1位置处的元素一定比他大,j这个位置的元素已经确认比他小了,所以交换,这下才使得小的在左边,大的在右边。
exch(a, lo, j);
// 返回基准元素的最新位置,方便对他的左右两边的子数组做递归处理
return j;
}
// Helper functions
private static boolean less(int v, int w) {
return v<w;
}
private static void exch(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//======================================================================
// 选择排序
public static void selectionSort(int[] nums){
int len= nums.length;
for (int i = 0; i < len-1; i++) {
int minIndex=i;
for (int j = i; j < len; j++) {
if (nums[j]<nums[i]){
minIndex=j;
}
}
exch(nums,i,minIndex);
}
}
//======================================================================
// 插入排序
public static void insertSort(int[] nums) {
int len= nums.length;
for (int i = 1; i < len; i++) {
int key= nums[i];
int Index=i-1;
while (Index>=0&&nums[Index]>key){
nums[Index+1]=nums[Index];
Index--;
}
nums[Index+1]=key;
}
}
//======================================================================
// shell排序
public static void shellSort(int[] nums) {
int n=nums.length;
for (int gap = n/2; gap >0; gap/=2) {
for (int i = gap; i < n; i++) {
int key=nums[i];
// int j=i;
int Index=i-gap;
// 对每个子数组进行插入排序
while (Index>=0&& nums[Index]>key){
nums[Index+gap]=nums[Index];
Index-=gap;
}
nums[Index+gap]=key;
}
}
}
}
public class Main{
public static void main(String[] args) {
int size = 50000-1; // 数组大小
int[] nums = new int[size];
// 生成从1到100000的数字数组
for (int i = 0; i < size; i++) {
nums[i] = size - i;
}
//===========================================================================
// 冒泡排序
System.out.println("冒泡排序");
System.out.println("Before sort,nums[]:");
System.out.println(Arrays.toString(nums));
System.out.println("After sort,nums[]: ");
int[] nums1=nums.clone();
// 计时器
Instant start = Instant.now();
sort.bubbleSort(nums1);
Instant end = Instant.now();
Duration time1 = Duration.between(start, end);
System.out.println("耗时"+time1.toMillis());
System.out.println(Arrays.toString(nums1));
System.out.println();
//===========================================================================
// 快速排序
System.out.println("快速排序");
System.out.println("Before sort,nums[]:");
System.out.println(Arrays.toString(nums));
System.out.println("After sort,nums[]: ");
int[] nums2=nums.clone();
// 计时器
start = Instant.now();
sort.qiuckSort(nums2);
end = Instant.now();
Duration time2 = Duration.between(start, end);
System.out.println("耗时"+time2.toMillis());
System.out.println(Arrays.toString(nums2));
System.out.println();
//===========================================================================
// 选择排序
System.out.println("选择排序");
System.out.println("Before sort,nums[]:");
System.out.println(Arrays.toString(nums));
System.out.println("After sort,nums[]: ");
int[] nums3=nums.clone();
// 计时器
start = Instant.now();
sort.selectionSort(nums3);
end = Instant.now();
Duration time3 = Duration.between(start, end);
System.out.println("耗时"+time3.toMillis());
System.out.println(Arrays.toString(nums3));
System.out.println();
//===========================================================================
// 插入排序
System.out.println("插入排序");
System.out.println("Before sort,nums[]:");
System.out.println(Arrays.toString(nums));
System.out.println("After sort,nums[]: ");
int[] nums4=nums.clone();
// 计时器
start = Instant.now();
sort.insertSort(nums4);
end = Instant.now();
Duration time4 = Duration.between(start, end);
System.out.println("耗时"+time4.toMillis());
System.out.println(Arrays.toString(nums4));
System.out.println();
//===========================================================================
// shell排序
System.out.println("希尔排序");
System.out.println("Before sort,nums[]:");
System.out.println(Arrays.toString(nums));
System.out.println("After sort,nums[]: ");
int[] nums5=nums.clone();
// 计时器
start = Instant.now();
sort.shellSort(nums5);
end = Instant.now();
Duration time5 = Duration.between(start, end);
System.out.println("耗时"+time5.toMillis());
System.out.println(Arrays.toString(nums5));
System.out.println();
System.out.println();
System.out.println("===========================================================================================");
System.out.println("耗时分别如下:");
System.out.println("冒泡排序time1 = " + time1.toMillis());;
System.out.println("快速排序time2 = " + time2.toMillis());
System.out.println("选择排序time3 = " + time3.toMillis());
System.out.println("插入排序time4 = " + time4.toMillis());
System.out.println("希尔排序time5 = " + time5.toMillis());
}
}
测试结果
二、测试细节
🌈7.处理输出
1.标准ACM模式
public static void main(String[] args) {
System.out.println("Enter Nums[]'s length:");
Scanner scanner = new Scanner(System.in);
int length=scanner.nextInt();
int[] nums = new int[length];
System.out.println("Enter Nums[]'s :");
for (int i = 0; i < length; i++) {
nums[i]=scanner.nextInt();
}
System.out.println("Before sort,nums[]:");
System.out.println(Arrays.toString(nums));
System.out.println("After sort,nums[]: ");
Instant start = Instant.now();
bubbleSort(nums);
Instant end = Instant.now();
Duration elapsed = Duration.between(start, end);
long time = elapsed.toMillis();
System.out.println(Arrays.toString(nums));
System.out.println("整个过程耗时"+time+"ms");
}
}
2.基于自动模式
public static void main(String[] args) {
int size = 10000; // 数组大小
int[] nums = new int[size];
// 生成从1到100000的数字数组
for (int i = 0; i < size; i++) {
nums[i] = size-i;
}
System.out.println("Before sort,nums[]:");
System.out.println(Arrays.toString(nums));
System.out.println("After sort,nums[]: ");
Instant start = Instant.now();
bubbleSort(nums);
Instant end = Instant.now();
Duration elapsed = Duration.between(start, end);
long time = elapsed.toMillis();
System.out.println(Arrays.toString(nums));
System.out.println("整个过程耗时"+time+"ms");
}
}
🌈8.时间处理
(四大步)
记住Instant()、Duration()、toMillis()
Instant start = Instant.now();
Instant end = Instant.now();
Duration elapsed = Duration.between(start, end);
long time = elapsed.toMillis();
三、踩坑事项@
1、数组转字符串:
Arrays.toString(nums)
2.修改默认栈大小@
在测试中初始化了一个50000个元素的数组,栈直接报错了StockOverflawErrer。
这里需要修改默认的1M为100M。默认的也太小了。
修改步骤
成功完成。
3.时间的处理
最后的Duration如果不转化为toMillis()的的话很不友好,如下:
转化后:
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖
热门专栏推荐
🌈🌈JAVA基础要夯牢 关注走一波💕💕
🌈🌈JAVA后端技术栈 关注走一波💕💕
🌈🌈JAVA面试八股文 关注走一波💕💕
🌈🌈代码随想录精讲200题 关注走一波💕💕
🌈🌈JAVA项目(含源码深度剖析) 关注走一波💕💕
🌈🌈计算机四件套 关注走一波💕💕
🌈🌈必知必会工具集 关注走一波💕💕
🌈🌈书籍网课笔记汇总 关注走一波💕💕
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!