无论是在面试中还是笔试的算法题中,或者竞赛的算法题中都会多多少少和这基本的8大排序有关,下列就这8大排序做一简单的介绍(Java实现),首先看一下基本的分类:
本文的顺序是按照本人理解的由简单到难而写的
1.直接插入排序
算法思想:这是一个向有序区间中插入一个元素的排序过程,设有n个数据的待排区间arr[0]~arr[n-1],则应该初始值arr[0]这一个元素作为一个有序的区间,arr[1]~arr[n-1]是无序的,然后从arr[1]开始遍历,拿到元素后和有序空间的值进行比较(注意这里和有序空间倒着比较会更好),比较后把该元素插入到合适的位置,然后有序数组有多一个元素,直至遍历完则排序结束。
例如:有数组arr[]={3,2,5,8,4,7,6},从第二个元素开始比较:
i=2时:2,3,5,8,4,7,6
i=3时:2,3,5,8,4,7,6
i=4时:2,3,5,8,4,7,6
i=5时:2,3,4,5,8,7,6
...以此类推
代码如下:
public static void insertSort(int[] arr) {//直接插入排序函数
int i,j;
for(i=1;i<arr.length;i++) {//从第二个元素开始遍历
int x=arr[i];//元素移动之前先把当前元素保存起来,防止移动时覆盖
for(j=i-1;j>=0;j--) {//和当前遍历元素的前面的区间比较大小,直至找到合适的位置
if(arr[j]>arr[i]) {
arr[j+1]=arr[j];
}
else {
break;
}
}
arr[j+1]=x;//把当前遍历元素放入到合适的位置上
}
}
public static void printArray(int[] arr) {//输出函数
for(int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args) {
int[] arr= {3,2,5,8,4,7,6};
insertSort(arr);
printArray(arr);
}
时间复杂度:o(n^2),稳定性:稳定
2.直接选择排序法
算法思想:在一个乱序数组中,遍历数组,找到这个数组的最小值(或者最大值),然后和第一个元素进行交换(arr[0]=min/max),接着从数组中剩下的元素中继续找最小值(最大值),和第二个元素进行交换...以此类推。
例如:有数组arr[]={3,2,5,8,4,7,6}
第一次:2,3,5,8,4,7,6
第二次:2,3,5,8,4,7,6
第三次:2,3,4,8,5,7,6
......
代码如下:
public static void selectSort(int[] arr) {
for(int i=0;i<arr.length-1;i++) {
int pmin=i;//初始化
for(int j=i+1;j<arr.length;j++) {
if(arr[j]<arr[pmin])pmin=j;//获得最小值得下标(即就得到了最小值)
}
if(i!=pmin) {//为了防止两个相同的数交换,加个判断
int temp=arr[i];
arr[i]=arr[pmin];
arr[pmin]=temp;
}
}
}
public static void printSort(int[] arr) {
for(int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args) {
int[] arr= {3,2,5,8,4,7,6};
selectSort(arr);
printSort(arr);
}
时间复杂度:o(n^2),稳定性:不稳定
3.冒泡排序法
算法思想:在一个无序的数组中,自上向下的相邻的两个数进行比较交换,让小的值冒上来,让大的值沉到底,即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
例如:有数组arr[]={3,2,5,8,4,7,6},根据数组的特点我们可以尝试着从后往前跑(即7和6相比后交换,4和6相比交换...)
第一次:2,3,4,5,8,6,7
第二次:2,3,4,5,6,8,7
第三次:2,3,4,5,6,7,8
代码如下:
public static void bubbleSort(int[] arr) {
int tag=1;
for(int i=0;tag==1&&i<arr.length-1;i++) {//使用tag的目的就是是,这个操作比较3次就排好序了,就可以结束了,不让程序在在哪来两两比较
tag=0;
for(int j=arr.length-1;j>i;j--) {
if(arr[j-1]>arr[j]) {//当排序完成或者j率先等于-1时,这段不执行,然后tag=0;结果上层的for循环直接结束
int temp=arr[j-1];
arr[j-1]=arr[j];
arr[j]=temp;
tag=1;
}
}
}
//下面这段代码是我常用的排序的,思想类似于冒泡排序法(更重要的是好记)
/*for(int i=0;i<arr.length-1;i++) {
for(int j=i+1;j<arr.length;j++) {
if(arr[i]>arr[j]) {
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}*/
}
public static void printSort(int[] arr) {
for(int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
}
public static void main(String[] args) {
int[] arr= {3,2,5,8,4,7,6};
bubbleSort(arr);
printSort(arr);
}
时间复杂度:o(n^2),稳定性:稳定
4.堆排序
算法思想:首先应该明确大根堆(大顶堆),小根堆(小顶堆);大根堆是建立在二叉树的一种结构,即每个根节点的值比左右子女的值大就是大根堆,每个根节点的值比左右子女的值小就是小根堆。第一步:将一个无序数组要构成一个大根堆,此时根节点的值是最大的;第二步:把最大值与二叉树中最后一个叶子节点进行交换,此时最后一个叶子节点就是最大值;第三歩:把剩下的n-1个元素继续用这种办法不断调整,直至排成有序的序列。如下图:
对于一个无序的数组arr[]={4,6,8,5,9};并且应该熟知二叉树的一个性质:假设arr[i]是根节点,arr[2*i+1]即他的左子女,arr[2*i+2]是他的右子女。大根堆要满足:arr[i]>arr[2*i+1]&&arr[i]>arr[2*i+2]
步骤一:调整成大根堆
1.假定无序数组是这样的:
2.我们从最后一个非叶子节点进行调整,直至调整至根节点结束(arr.length/2-1=1)
此时一个大根堆已经构建成功
步骤二:将最后一个节点和根节点进行交换,继续重建大根堆,交换....
直至调整成:
简单的总结一下思路:
1.将一个无序数组构建成一个大根堆;
2.将根节点和最后一个叶子节点进行交换,将最大的元素“沉底”;
3.重新构建成一个大根堆,然后交换根节点元素和当前末尾元素,不断调整、交换直至有序。
代码如下:
public class HeapSort {
public static void Sort(int[] arr) {
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--) {
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>=0;j--) {
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
//调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
public static void adjustHeap(int[] arr,int i,int length) {
int temp=arr[i];//先取出当前元素i
for(int k=2*i+1;k<length;k=k*2+1) {//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length&&arr[k]<arr[k+1]) {//如果左子节点小于右子节点,k指向右子结点
k++;
}
if(arr[k]>temp) {//如果子节点大于父节点,将子节点赋值给父节点(不用进行交换)
arr[i]=arr[k];
i=k;
}
else {
break;
}
}
arr[i]=temp;
}
//交换堆顶元素和末尾元素
public static void swap(int[] arr,int x,int y) {
int temp=arr[x];
arr[x]=arr[y];
arr[y]=temp;
}
public static void main(String[] args) {
int[] arr= {3,2,5,8,4,7,6,9,1,0};
Sort(arr);
System.out.println(Arrays.toString(arr));
}
}
时间复杂度:o(nlogn),稳定性:不稳定
未完待续。。。