目录
*************************************华丽的分割线*********************************************
各种排序算法效率
各种常用排序算法 | ||||||||
类别 | 排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | 复杂性 | 特点 | ||
最好 | 平均 | 最坏 | 辅助存储 |
| 简单 |
| ||
插入 排序 | 直接插入 | O(N) | O(N2) | O(N2) | O(1) | 稳定 | 简单 |
|
希尔排序 | O(N) | O(N1.3) | O(N2) | O(1) | 不稳定 | 复杂 |
| |
选择 排序 | 直接选择 | O(N) | O(N2) | O(N2) | O(1) | 不稳定 |
|
|
堆排序 | O(N*log2N) | O(N*log2N) | O(N*log2N) | O(1) | 不稳定 | 复杂 |
| |
交换 排序 | 冒泡排序 | O(N) | O(N2) | O(N2) | O(1) | 稳定 | 简单 | 1、冒泡排序是一种用时间换空间的排序方法,n小时好 |
快速排序 | O(N*log2N) | O(N*log2N) | O(N2) | O(log2n)~O(n) | 不稳定 | 复杂 | 1、n大时好,快速排序比较占用内存,内存随n的增大而增大,但却是效率高不稳定的排序算法。 | |
归并排序 | O(N*log2N) | O(N*log2N) | O(N*log2N) | O(n) | 稳定 | 复杂 | 1、n大时好,归并比较占用内存,内存随n的增大而增大,但却是效率高且稳定的排序算法。 | |
基数排序 | O(d(r+n)) | O(d(r+n)) | O(d(r+n)) | O(rd+n) | 稳定 | 复杂 |
| |
注:r代表关键字基数,d代表长度,n代表关键字个数 |
1.插入排序
思想:假设前面的都是有序的,依次将后面的无序的数,插入前面有序的。
public static void insertSort(int[] a) {
int j = 0;
for (int i = 1; i < a.length; i++) {
int temp = a[i];
for (j = i-1; j >= 0 ; j--) {
if(a[j]>temp) {//如果a[j]>temp,依次向后移动
a[j+1] = a[j];//记录j的值就是temp要插入的地方
}else {
break;
}
}
a[j+1] = temp;//由于j--,所以要加一
}
}
2.选择排序
思路:在一组要排序的数组中,找到最小的一个与第一个交换,依次类推,直到数组中倒数第二个和第一个比较为止。
public static int[] sortSelect(int[] a) {
for (int i = 0; i < a.length; i++) {
int temp;
for (int j = i+1; j < a.length; j++) {
if(a[i]>a[j]) {//如果满足条件,则交换
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
return a;
}
/**
* 优化后的
* @param a
* @return
*/
public static int[] sortSelect(int[] a) {
int temp = 0;
for (int i = 0; i < a.length; i++) {
int index = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[index]) //先不交换,找出最小的索引,存起来
index = j;
}
if (i != index) //如果i和索引不相同,交换位置
temp = a[i];
a[i] = a[index];
a[index] = temp;
}
return a;
}
3.冒泡排序
思路:冒泡排序就是把小的元素往前调或者把大的元素往后调。
public static int[] sortBubble(int[] a) {
int temp;
for (int i = 1; i < a.length ; i++) { // 外循环为排序趟数,len个数进行len-1趟
for (int j = 0; j < a.length - i; j++) { //内循环为每趟比较的次数,第i趟比较len-i次
if (a[j] > a[j + 1]) //相邻元素比较,若逆序则交换(升序为左大于右,降序反之)
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
return a;
}
4.快速排序
思路:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,
将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其
排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。
public static void quickSort(int[] a,int low,int high) {
int i,j,temp,t;
if(low>high) {
return; //如果low>high,退出调用
}
i = low;
j = high;
temp = a[low];//将第一个数作为基准数
while(i<j) {
//从右往左,大于基准数,依次减一
while(temp<=a[j]&&i<j) {
j--;
}
//从左往右,小于基准数,依次加一
while(temp>=a[i]&&i<j) {
i++;
}
//如果满足条件,则交换
if(i<j) {
t = a[j];
a[j] = a[i];
a[i] = t;
}
}
//最后将基准为与i和j相等位置的数字交换
a[low] = a[i];
a[i] = temp;
quickSort(a, low, j-1); //递归调用左半数组
quickSort(a, j+1, high);//递归调用右左半数组
}
5.希尔排序
思路:首先它把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高
详解:https://blog.csdn.net/qq_39207948/article/details/80006224
public static void shellSort(int[] a) {
int N = a.length;
//进行分组,最开始的增量(gap)为数组长度的一半
for (int gap = N/2; gap > 0; gap /=2) {
//对各个分组进行插入排序
for (int i = gap; i < N; i++) {
int temp = a[i];
int j;
for (j = i-1; j >= 0 ; j--) {
if(a[j]>temp) {//如果a[j]>temp,依次向后移动
a[j+1] = a[j];//记录j的值就是temp要插入的地方
}else {
break;
}
}
a[j+1] = temp;//由于j--,所以要加一
}
}
}
public class ShellSort {
public static void main(String[] args) {
int[] a = {2,1,4,7,9,6,8,0};
int N = a.length;
for(int gap=N/2;gap>0;gap--) {
InsertSort(a, gap);
}
System.out.println(Arrays.toString(a));
}
public static void InsertSort(int a[],int gap) {
for(int i=gap;i<a.length;i++) {
int temp = a[i];
int j;
for(j=i-1; j >= 0 ; j--) {
if(temp<a[j]) {
a[j+1] = a[j];
}else {
break;
}
}
a[j+1] = temp;
}
}
}
******************************************************华丽的分割线*****************************************************************
6.折半插入排序
原理:二分法寻找插入顺序,插入排序插入数据。
public static int[] binSearchSort(int[] a){
int n = a.length;
int i,j;
for (i = 1; i < n; i++) {//插入排序,遍历序列,从第二个开始
int temp = a[i];
int left = 0;
int right = i-1;
while(left<=right) { //二分查找选择插入位置
int mid = (left+right)/2;
if(a[mid]>temp) {
right = mid-1;
}else {
left = mid+1;
}
}
for(j = i-1;j>=left;j--)
a[j+1] = a[j];//腾出插入位置
a[j+1] = temp;//赋值
}
return a;
}
7.归并排序
基本思路:将数组分解成A,B两个数组,假设A,B两个数组都是有序的,那么将这两个数组比较排序就好了,假设有一个数组为空,那么把剩下的那个数组拿过来放到后面就行了。那么怎么才能使这个数组有序那,继续将这两个数组递归,递归到数组中只有一个元素时,这时数组就有序了,然后我们再把相邻的数组合并,这个数组就变成有序数组了。
思路我们说完了,那么我们先来解决第一个问题,相邻数组的合并。
void MemeryArray(int[] a,int n,int[] b,int m,int[] c) {
int i=0,j=0,k=0;
while(i<n&&j<m) {//合并两个相邻数组
if(a[i]<b[j]) {
c[k++] = a[i++];
}else {
c[k++] = b[j++];
}
}
while(i<n) {//如果b数组空,直接将a数组拿到c数组中
c[k++] = a[i++];
}
while(j<m) {//如果a数组空,直接将b数组拿到c数组中
c[k++] = b[j++];
}
}
解决了数组的合并,那接下来的重点就是将数组递归分割成一个一个的小数组了。
static void memger(int[] a,int l,int r,int[] t) {
if(l<r) {//递归分割成含有一个元素的数组,然后在合并
int m = (l+r)/2;
memger(a, l, m,t);//分割左数组
memger(a, m+1, r,t);//分割右数组
mergerArray(a,l,m,r,t);//合并数组
}
}
接下来只要在修改一下我们的合并数组的方法就可以了,很简单,只要加一个for循环赋值就可以了。
static void mergerArray(int[] a,int l,int m,int r,int[] temp){
int i = l,j = m+1;
int k = 0;
while(i<=m&&j<=r) {
if(a[i]<=a[j]) {
temp[k++] = a[i++];
}else {
temp[k++] = a[j++];
}
}
while(i<=m) {
temp[k++] = a[i++];
}
while(j<=r) {
temp[k++] = a[j++];
}
for (i = 0; i < k; i++)
a[l + i] = temp[i]; //递归的过程中,l有可能不为0
}
测试用例
public static void main(String[] args) {
int[] test = {9,2,6,3,5,7,10,11,12};
int[] temp = new int[test.length];
memger(test,0,test.length-1,temp);
for (int i = 0; i < temp.length; i++) {
int j = test[i];
System.out.print(j+",");
}
}
8.二叉树排序
原理:构造树的过程就是排序的过程,在构造过程中,比根小的是左子树,比根大的是右子树。所以中序遍历就是有序的序列
package cn.datastruct.tree;
public class BinTreeSort {
private static Node root;
class Node {
private int val;
private Node lTree;
private Node rTree;
public Node(int val) {
this.val = val;
}
}
public boolean addNode(int val) { //建立二叉树
Node node = new Node(val);
if (root == null) {
root = node;
return true;
} else {
Node cur = root;
while (true) {
if (cur.val > val) {
if(cur.lTree==null) {
Node newNode = new Node(val);//新建准备赋给左子树的结点
cur.lTree = newNode;
return true;
}
cur = cur.lTree;
} else {
if (cur.val < val) {
if(cur.rTree==null) {
Node newNode = new Node(val);//新建准备赋给右子树的结点
cur.rTree = newNode;
return true;
}
cur = cur.rTree;
} else {
return false;//不允许重复
}
}
}
}
}
/**
* 中序
* @param node
*/
public void inOrder(Node node) {
if(node==null) {
return;
}
inOrder(node.lTree);
System.out.println(node.val);
inOrder(node.rTree);
}
public static void main(String[] args) {
BinTreeSort tree = new BinTreeSort();
int[] a = new int[] { 3, 1, 0, 2, 7, 5, 8, 9 };
for (int i : a) {
tree.addNode(i);
}
tree.inOrder(root);
}
}
*************************************华丽的分割线*********************************************
9.基数排序
10.堆排序
去TM的。。。。。。。。。。。