Go最全数据结构——八大排序算法(面试必备)_八大排序面试哪些,Golang 400道面试题通关宝典助你进大厂

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

    if (!flag)
        break;
    else
        flag = false;//重置flag,进行下次判断
}

}


* **时间复杂度**:O(n^2)
* 稳定




---


  

### 2. 交换排序——快速排序



> 
> 快速排序(Quicksort)是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
> 
> 
> ![image-20210319133541591](https://gitee.com/zhong_siru/images/raw/master//img/image-20210319133541591.png)
> 



public static void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
int pivot = arr[(left + right) / 2];
//while循环是为了让比pivot小的值放其左边,比pivot大的值放其右边
while (l < r) {
while (arr[l] < pivot)//直到找到比pivot小的数
l++;
while (arr[r] > pivot)//直到找到比pivot大的数
r–;
if (l >= r)//说明比pivot小的值都在其左边,比pivot大的值都在其右边
break;
//找到pivot左边比其大的元素,右边比其小的元素;进行交换
int t = arr[l];
arr[l] = arr[r];
arr[r] = t;
}
//如果l==r,则要l++、r–;否则会出现栈溢出
if (l == r) {
l++;
r–;
}
//向左递归
if (left < r)
quickSort(arr, left, r);
//向右递归
if (right > l)
quickSort(arr, l, right);
}


* **时间复杂度**:O(nlog2n)
* 不稳定




---


  

### 3. 选择排序——简单选择排序



> 
> **基本思想**:
> 
> 
> * 第一次从 arr[0]~arr[n-1]中选取最小值,与 arr[0]交换
> * 第二次从 arr[1]~arr[n-1]中选取最小值,与 arr[1]交换
> * 第三次从 arr[2]~arr[n-1]中选取最小值,与 arr[2] 交换…
> * 第 i 次从 arr[i-1]~arr[n-1]中选取最小值,与 arr[i-1]交换…
> * 第 n-1 次从 arr[n-2]~arr[n-1]中选取最小值,与 arr[n-2]交换
> 
> 
> 
> 
> ---
> 
> 
> 总共通过 n-1 次,得到一个按排序码从小到大排列的有序序列
> 
> 
> ![image-20210319083754641](https://img-blog.csdnimg.cn/img_convert/4c73607b372f4d1d78a8bf8dcee363af.png)
> 
> 
> 



public void selectSort(int[] arr){
for (int i = 0; i < arr.length - 1; i++) {
int min = arr[i];//假设当前值最小
int minIndex = i;//记录最小值的索引
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < min) {
min = arr[j];
minIndex = j;
}
}
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}


* **时间复杂度**:O(n^2)
* 不稳定




---


  

### 4. 选择排序——堆排序



> 
> 堆排序是利用`堆`这种数据结构而设计的一种排序算法,堆排序是一种**选择排序,**它的最坏,最好,平均时间复杂度均为O(nlogn),它也是**不稳定**排序。
> 
> 
> 


#### 什么是堆


堆是具有以下性质的`完全二叉树`


1️⃣ **每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆(没有要求结点的左孩子的值和右孩子的值的大小关系)**



arr[i] >= arr[2*i+1] && arr[i] >= arr[2*i+2] //i对应第几个节点,i从0开始编号


![image-20210424144039570](https://gitee.com/zhong_siru/images/raw/master//img/image-20210424144039570.png)
我们对堆中的结点按层进行编号,映射到数组中就是下面这个样子:


![image-20210424144100653](https://gitee.com/zhong_siru/images/raw/master//img/image-20210424144100653.png)
2️⃣ **每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆**



arr[i] <= arr[2*i+1] && arr[i] <= arr[2*i+2] //i对应第几个节点,i从0开始编号


![image-20210326154415576](https://gitee.com/zhong_siru/images/raw/master//img/image-20210326154415576.png)
#### 堆排序基本思想


1. 将待排序序列构造成一个**大顶堆**
2. 此时,整个序列的最大值就是堆顶的根节点。
3. 将其与末尾元素进行交换,此时末尾就为最大值。
4. 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。


一般升序采用大顶堆,降序采用小顶堆


#### 步骤图解



> 
> **步骤一:构造初始堆,将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)**
> 
> 
> 


**原始的数组 [4, 6, 8, 5, 9]**


1. 假设给定无序序列结构如下


![image-20210326155955170](https://img-blog.csdnimg.cn/img_convert/e593384fe14a6e0f09ced26e0f84b9f0.png)


2. 此时我们从最后一个非叶子结点开始(叶结点不用调整,第一个非叶子结点 `arr.length/2-1`=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整


![image-20210326160041965](https://img-blog.csdnimg.cn/img_convert/f3834d1b7f845515aa8361ea8a5181b6.png)


3. 找到第二个非叶节点 4,由于[4,9,8]中 9 元素最大,4 和 9 交换


![image-20210326160136378](https://img-blog.csdnimg.cn/img_convert/27875bee2bbd31ac6c4c2a5551d113b5.png)


4. 这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中 6 最大,交换 4 和 6


![image-20210326160201923](https://img-blog.csdnimg.cn/img_convert/b0a93a57905592c3142745022975bb89.png)


此时,我们就将一个无序序列构造成了一个大顶堆



> 
> **步骤二:将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换**
> 
> 
> 


1. 将堆顶元素 9 和末尾元素 4 进行交换


![image-20210326160301786](https://img-blog.csdnimg.cn/img_convert/eef17318b4e65fd97a9664fdf7f04ed5.png)


2. 重新调整结构,使其继续满足堆定义


![image-20210326160319608](https://img-blog.csdnimg.cn/img_convert/96fa14c6d9c4d3e3032b2e3c999ab649.png)


3. 再将堆顶元素 8 与末尾元素 5 进行交换,得到第二大元素 8


![image-20210326160340143](https://img-blog.csdnimg.cn/img_convert/4562e34528065a90d697b578be563531.png)


4. 后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序


![image-20210326160358981](https://img-blog.csdnimg.cn/img_convert/212104c7f5e7d1a9aa3f6dc65cac7e34.png)


#### 代码实现



import java.util.Arrays;

public class HeapSort {
public static void main(String[] args) {
int[] arr = {3, 5, 2, 7, 8, 0, -1, 99};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}

//堆排序
public static void heapSort(int[] arr) {
    //将无序序列构建成一个堆
    for (int i = arr.length / 2 - 1; i >= 0; i--) {
        adjustHeap(arr, i, arr.length);
    }
    //将堆顶元素和末尾元素交换,将最大元素放置数组末端
    //重新调整至堆结构,然后继续将堆顶元素和当前末尾元素交换,以此往复
    for (int i = arr.length - 1; i > 0; i--) {
        int temp = arr[i];
        arr[i] = arr[0];
        arr[0] = temp;
        adjustHeap(arr, 0, i);
    }
}

/\*\*

* 将二叉树调整为堆
*
* @param arr 待调整的数组
* @param i 表示非叶子结点在数组中索引
* @param length 表示对多少个元素继续调整,length逐渐减少
*/
public static void adjustHeap(int[] arr, int i, int length) {
int temp = arr[i];
//k=2i+1是i的左子节点
for (int k = i * 2 + 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为父结点的树的最大值,放在了顶部
arr[i] = temp;//将temp值放到调整后的位置
}
}




---


  

### 5. 插入排序——简单插入排序



> 
> **基本思想**:把 n 个待排序的元素看成为一个`有序表`和一个`无序表`,开始时 有序表 中只包含一个元素,无序表中包含有 n-1 个元素,排序过程中每次从无序表中取出第一个元素,与有序表中的元素进行比较,将它插入到有序表中的适当位置,使之成为新的有序表
> 
> 
> ![image-20210424142159599](https://gitee.com/zhong_siru/images/raw/master//img/image-20210424142159599.png)
> 



public void InserSort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int insertVal = arr[i];//待插入左边有序表的数
int left_index = i - 1;//左边有序表的索引,初值为有序表最右数的索引
while (left_index >= 0 && insertVal < arr[left_index]) {//不断遍历左边的有序表进行比较
arr[left_index + 1] = arr[left_index];//比较过的值右移
left_index–;//索引-1,继续比较
}
if (left_index + 1 != i)
arr[left_index + 1] = insertVal;
}
}


* **时间复杂度**:O(n^2)
* 稳定




---


  

### 6. 插入排序——希尔排序



> 
> 简单的插入排序可能存在的问题:当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响
> 
> 
> 
> ```
> # 比如数组 arr = {2,3,4,5,6,1} 这时需要插入的数 1(最小),这样的过程是
> {2,3,4,5,6,6} 
> {2,3,4,5,5,6} 
> {2,3,4,4,5,6} 
> {2,3,3,4,5,6} 
> {2,2,3,4,5,6} 
> {1,2,3,4,5,6}
> 
> ```
> 
> 为了改进,提出了希尔排序算法:
> 
> 
> `希尔排序`是希尔(Donald Shell)于 1959 年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为`缩小增量排序`
> 
> 
> ![image-20210319130542037](https://img-blog.csdnimg.cn/img_convert/432c9d65aa09431dc64c898cc8edaa3e.png)![image-20210319130703912](https://img-blog.csdnimg.cn/img_convert/49121d51c58498902472a2de543e4b68.png)
> 
> 
> 



//交换式
public void shellSort(int[] arr){
for(int gap=arr.length/2;gap>0;gap/=2){ //步长gap逐次递减
for(int i=gap;i<arr.length;i++){
for(int j=i-gap;j>=0;j-=gap){
if(arr[j]>arr[j+gap]){
int t=arr[j];
arr[j]=arr[j+gap];
arr[j+gap]=t;
}
}
}
}
}

//改进成移位法
public void shellSort(int[] arr){
for (int gap = arr.length / 2; gap > 0; gap /= 2) {//步长gap逐次递减
for (int i = gap; i < arr.length; i++) {
int left_index = i - gap;//左边有序表的索引,初值为有序表最右数的索引
int insertVal = arr[i];//要插入的值
while (left_index >= 0 && insertVal < arr[left_index]) {
arr[left_index + gap] = arr[left_index];//比较过的值右移
left_index -= gap;
}
arr[left_index + gap] = insertVal;
}
}
}


* **时间复杂度**:O(nlog2n)
* 不稳定





![img](https://img-blog.csdnimg.cn/img_convert/aec94dc9c10a8dccc5ba06571b2913f9.png)
![img](https://img-blog.csdnimg.cn/img_convert/c88377235253b35510d29b7fd7641f24.png)
![img](https://img-blog.csdnimg.cn/img_convert/ab4069d1337f4fd4a98ee189d02c608e.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**

  }
            arr[left_index + gap] = insertVal;
        }
    }
}

  • 时间复杂度:O(nlog2n)
  • 不稳定

[外链图片转存中…(img-3px75vc9-1715828088618)]
[外链图片转存中…(img-LIUNa8wS-1715828088618)]
[外链图片转存中…(img-df5VRg5K-1715828088618)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值