前言
七大排序作为排序的基础,也是大厂面试管喜欢提问的方式,很多同学只懂得部分排序的思想,却不一定能在面试的过程中手撕代码,秋招临近,借此机会手撕一遍以巩固思想
冒泡排序
核心思想:对于长度为n的数组,在每一次遍历的过程中,都将较大的数往后进行交换,再遍历到最后一位的过程中,最大的数就排列在末尾了。注意:一边遍历一遍交换数字顺序,是冒泡的思想,不要与下面的插入排序混淆(网上很多排序出现了错误,不要被误导).附上偷来的动图

static void maopao(int []a){
for (int i = a.length - 1; i > 0 ; i--) {
boolean change = false;//优化,记录每次遍历过中是否发生过交换
for (int j = 0; j < i; j++) {
if (a[j] > a[j+1]){
swap(a,j,j+1);
change = true;
}
}
if (!change) return;//若无交换,说明排序成功
}
}
static void swap(int []a,int i,int j){
int b = a[i];
a[i] = a[j];
a[j] = b;
}
快速排序
核心思想:选用递归思想。先选定一个数字(一般选择末尾数),找到其位置,将该位置上的数字与末尾选定数交换。再对该数左右两侧重复同样的动作。难点在于,是如何找到其位置的:设定两个指针,从数组头尾进行遍历,头部指针一旦找到比选定数字大的,停下,同时尾部指针找到比选定数字小的,停下,将指针所指向数字进行交换。重复上述操作,直到头尾指针重合。上述操作进行的结果是:比选定数字小的,均在其左侧,比选定数字大的,均在其右侧,以及收尾指针相交处,即是该选定数字最终所在的位置。附上偷来的图

static void Kuaipai(int[] a, int start, int end) {
if (start >= end) return;
int mid = fenzu(a, start, end);
Kuaipai(a, start, mid - 1);
Kuaipai(a, mid, end);
}
static int fenzu(int[] a, int start, int end) {
int num = a[end];
int end1 = end;//记录末尾数位置
while (start < end) {
while (a[start] < num && start != end) start++;
while (a[end] >= num && end != start) end--;
if (start != end) {
swap(a, start, end);
}
}
swap(a, end1, start);
return start;
}
static void swap(int []a,int i,int j){
int b = a[i];
a[i] = a[j];
a[j] = b;
}
插入排序
核心思想:假定前面的数列已经排序完毕,将后面的数字插入到前面已排序的数组中适合他的位置。注:图中数字在下往前移动的时候,并非是交换了位置,不要错误理解

static void Charu(int[] a) {
for (int i = 1; i < a.length; i++) {
int j = i;
int temp = a[j];
while (j > 0 && a[j - 1] > temp) {
a[j] = a[j - 1];
j = j - 1;
}
a[j] = temp;
}
}
希尔排序
核心思想:希尔排序是在插入排序的基础上,人为的将数组进行了逻辑的的划分,每一次划分之后使用插入排序进行该逻辑上的分组,最后在划分间隔为1时,相当于做了一次插入排序(在基本有序的基础上)。

static void Xier(int[] a) {
for (int step = a.length / 2; step >= 1; step /= 2) {
Charu(a, step);
}
}
static void Charu(int[] a, int step) {
for (int i = step; i < a.length; i = i + 1) {
int j = i;
int temp = a[j];
while (j - step >= 0 && a[j - step] > temp) {
a[j] = a[j - step];
j = j - step;
}
a[j] = temp;
}
}
简单选择排序
核心思想:遍历一遍数组,找到最大的数字(或者最小数),将其放在最后(最前),依次类推,完成排序。注:注意与冒泡排序的区别,虽然每一趟都是完成了最大数的摆放,但是冒泡排序过程中包含了一边遍历,一遍将其有序化的操作(同样是遍历一次,但对数组进行的影响不同)

static void xuanze(int []a){
for (int i = 0; i < a.length; i++) {
int min = i;
for (int j = i; j < a.length; j++) {
if (a[j] < a[min]) min = j;
}
swap(a,i,min);
}
}
static void swap(int []a,int i,int j){
int b = a[i];
a[i] = a[j];
a[j] = b;
}
堆排序
核心思想:构造大根堆(小根堆):根节点大于(小于)左右字节点,整个树状结构都满足规律------>根节点为i,那么左子节点为2i + 1,右子节点为2i+2。以大根堆为例,从最后一个包含子节点的父节点开始(即非叶子节点的最后一个节点,i = length/2),遍历到根节点,依次完成大根堆构造,完成整个树状结构的大根堆结构。再将根节点与最后节点交换(相当于找到了最大数,放在了他应该在的位置),以0到n-1为堆,重新构造大根堆,依次循环,完成排序。

static void duipaixu(int []a){
//从非叶子节点的最后一个节点开始,下标为i/2,循环遍历至0号节点
for (int i = a.length / 2; i >= 0 ; i--) {
adjust(a,i,a.length);
}
for (int i = a.length - 1; i > 0; i--) {
//交换首尾
swap(a,0,i);
//调整第一个节点
adjust(a,0,i);
}
}
private static void adjust(int[] a, int start,int length) {
int temp = a[start];
int child = start * 2 +1 ;//左孩子
while (child < length) {
//如果存在右孩子,并且有孩子比左孩子大,则使用右孩子作为比较对象
if (child + 1 < length && a[child] < a[child + 1]) {
child = child + 1;
}
//如果孩子较大,交换,并且根据交换后是否有孩子判断是否要继续
if (temp < a[child]) {
swap(a, start, child);
//如果交换后的节点存在孩子节点,则重新赋值并继续循环
if (child * 2 + 1 < length){
start = child;
temp = a[start];
child = start * 2 + 1;
}else break;
} else {
//当前节点已经符合根节点最大,无须继续
break;
}
}
}
static void swap(int []a,int i,int j){
int b = a[i];
a[i] = a[j];
a[j] = b;
}
并归排序
核心思想:将数组分为左右两个已经排序好的数组,并对两个数组进行合并。难点在于递归的思想以及寻找出口:当且仅当首下标大于尾下标时,进行分组并合并,否则视为已完成。

static void bingguipaixu(int []a,int start,int end){
if (start < end){
int mid = (start + end) /2;
bingguipaixu(a,start,mid);
bingguipaixu(a,mid + 1,end);
merge(a,start,mid,end);
}
}
//左右两边已经排序完成,代码可简化(简化后思路不够清晰)
static void merge(int []a,int start,int mid,int end){
int []b = new int[end - start + 1];
int p = start;
int q = mid + 1;
int r = 0;
while (p <= mid && q <= end){
if (a[p] <= a[q]){
b[r] = a[p];
p = p + 1;
}else{
b[r] = a[q];
q = q + 1;
}
r = r + 1;
}
if (p > mid) {
while (q <= end) {
b[r] = a[q];
r = r + 1;
q = q + 1;
}
}
if (q > end){//这边判断可以不写,因为如果上面成立,q一定 > end
while (p <= mid) {
b[r] = a[p];
r = r + 1;
p = p + 1;
}
}
for (int i = start ,j = 0; i <= end; i++,j++) {
a[i] = b[j];
}
}
结束语:
本文总结了Java版七大排序的写法,如有问题希望能不吝文字,多多交流。PS:都看到这里了,给个赞呗,鼓励一下^v^