更多内容可以到专栏查看:https://blog.csdn.net/sunshine543123/category_10899368.html
本博客中都是按照从小到大排列
1.冒泡排序
对序列中所有数实行前后元素对比,小的在前大的在后,这样从头到尾进行n-1次
public class bubbleSort {
public static void main(String[] args) {
int[] a={
1,34,79,3,78,20,5,2,50,71,66,21};
int len=a.length;
int temp=a[0];
for (int i = 0; i < len; i++) {
for (int j = 0; j < len-i-1; j++) {
if (a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for (int i = 0; i < len; i++) {
System.out.print(a[i]+",");
}
}
}
时间复杂度O(n^2)
2.直接选择排序(简单选择排序)
通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录交换
public class directSort {
public static void main(String[] args) {
int[] a={
1,34,79,3,78,20,5,2,50,71,66,21};
int min;
for (int i = 0; i < a.length; i++) {
min=i;
for (int j = i; j < a.length; j++) {
if (a[min]>a[j]){
min=j;
}
}
if (min!=i){
swap(a,i,min);
}
}
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+",");
}
}
public static void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
时间复杂度O(n^2)
3.插入排序
将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录数增1的有序表
public class insertSort {
public static void main(String[] args) {
int[] a={
34,79,3,78,20,5,2,50,71,66,21};
int temp;
int j;
for (int i = 1; i < a.length; i++) {
if (a[i]<a[i-1]){
temp=a[i];
for (j = i;j>0&&temp<a[j-1]; j--) {
a[j]=a[j-1]; //后移
}
a[j]=temp;
}
}
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+",");
}
}
}
最好时间复杂度O(n),最坏时间复杂度O(n^2)
4.希尔排序
在插入排序的基础上,将相隔某个增量的记录组成一个子序列,将子序列进行直接插入排序后得到基本有序序列(小的基本在前,大的基本在后),再对全体记录进行一次直接插入排序
public class ShellSort {
public static void main(String[] args) {
int[] a={
1,34,79,3,78,20,5,2,50,71,66,21};
int j,i;
int increment=a.length;
int temp;
do {
increment=increment/3+1; //增量序列 增量序列的最后一个值必须等于1
for (i=increment;i< a.length;i=i+increment){
if (a[i]<a[i-increment]){
temp=a[i]; //暂存在temp
for (j=i; j> 0 && temp<a[j-increment]; j=j-increment){
a[j]=a[j-increment];
}
a[j]=temp;
}
}
}while (increment>1);
for (i = 0; i < a.length; i++) {
System.out.print(a[i]+",");
}
}
}
时间复杂度O(n³/²)
5.堆排序
简单选择排序的升级
堆结构:
堆是具有下列性质的完全二叉树:每个节点的值都大于等于左右孩子结点值,称为大顶堆;每个节点的值都小于等于左右孩子结点值,称为小顶堆;
基本思想:将待排序列构建成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值,如此反复就能得到一个有序序列了。
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr={
50,10,90,30,70,40,80,60,20};
System.out.println("排序前:"+ Arrays.toString(arr));
//将arr构建为大顶堆
for (int i = arr.length/2-1; i >=0 ; i--) {
//从第一个有子节点的位置排序(从左到右,从下到上)
heapAdjust(arr,i,arr.length);
}
for (int j = arr.length-1; j>0 ; j--) {
swap(arr,0,j); //将当前堆中最大的和未排序的最后一个交换
heapAdjust(arr,0,j);
}
System.out.println("排序后:"+Arrays.toString(arr));
}
//实现大顶堆
public static void heapAdjust(int[] a,int i,int len){
int temp=a[i];//取出当前元素
for (int k=2*i+1;k<len;k=2*k+1){
//沿值较大的孩子结点向下筛选
if (k+1<len&&a[k]<a[k+1]){
//比较根节点a[i]的左右孩子大小
k=k+1; //记录较大的结点位置
}
if (temp > a[k]){
break; //比左右孩子结点大,不需要交换
}
//否则交换
a[i]=a[k];
a[k]=temp;
//若交换后的子节点存在子节点则继续进行排序(自上向下)
i=k;
}
}
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
时间复杂度O(n*logn)
6.归并排序
冒泡排序的升级
假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的的长度为1,然后两两归并,得到[n/2]个长度为2或1的子序列,再两两归并,…,如此重复知道得到一个长度为n的有序序列为止,这种排序方法被称为2路排序归并
使用递归算法:
import java.util.Arrays;
// 使用递归算法,先递归拆分再归并
public class MergeSort {
public static void main(String[] args) {
int[] arr={
50,10,90,30,70,40,80,60,20};
System.out.println("排序前:"+Arrays.toString(arr));
int[] TR1=new int[arr.length];
Msort(arr,TR1,0,arr.length-1);
System.out.println("排序后:"+ Arrays.toString(TR1));
}
public static void Msort(int[] arr,int[] TR1,int s,int t){
int m;
int[] TR2=new int[arr.length];
if (s==t){
TR1[s]=arr[s];
}
else{
m=(s+t)/2;
Msort(arr,TR2,s,m);
Msort(arr,TR2,m+1,t);
Merge(TR2,TR1,s,m,t);
}
}
//将有序的arr[i,m],arr[m+1,n]归并为有序的TR[i,n]
public static void Merge(int[] arr,int[] TR1,int i,int m,int n){
int j,k;
for (k=i,j=m+1;i<=m&&j<=n;k++){
if (arr[i]<arr[j]){
TR1[k]=arr[i];
i=i+1;
}
else{
TR1[k]=arr[j];
j=j+1;
}
}
while (i<=m){
TR1[k]=arr[i]; //将剩余的arr[i,m]复制到TR1[]
k++;
i++;
}
while (j<=n){
TR1[k]=arr[j]; 将剩余的arr[j,n]复制到TR1[]
k++;
j++;
}
}
}
减少空间复杂度的非递归算法
import java.util.Arrays;
/**
* 使用迭代,从最小的序列开始直至完成
*/
public class MergeSort2 {
public static void main(String[] args) {
int[] arr={
50,10,90,30,70,40,80,60,20};
System.out.println("排序前:"+Arrays.toString(arr));
int[] TR1=new int[arr.length];
int k=1;
while (k<arr.length){
MergePass(arr,TR1,k,arr.length);
k=2*k;
MergePass(TR1,arr,k,arr.length); //将归并到TR1中的序列再次两两归并回arr
k=2*k;
}
System.out.println("排序后:"+ Arrays.toString(arr));
}
public static void MergePass(int[] arr, int[] TR1, int s, int n){
//s指每个子序列的长度s={1,2,4...2k}(2k<n),n指整个序列的的长度
int i=0;
while (i <= n-2*s){
//两两归并的次数
Merge(arr,TR1,i,i+s-1,i+2*s-1);
i=i+2*s; //下一个两两归并序列的第一个元素
}
if (i<n-s){
//归并最后两个
Merge(arr,TR1,i,i+s-1,n-1);
}
else {
//只剩单个的一个子序列
for (int j = i; j < n; j++) {
TR1[j]=arr[j];
}
}
}
//将有序的arr[i,m],arr[m+1,n]归并为有序的TR[i,n]
public static void Merge(int[] arr,int[] TR1,int i,int m,int n){
int j,k;
for (k=i,j=m+1;i<=m&&j<=n;k++){
if (arr[i]<arr[j]){
TR1[k]=arr[i];
i=i+1;
}
else{
TR1[k]=arr[j];
j=j+1;
}
}
while (i<=m){
TR1[k]=arr[i]; //将剩余的arr[i,m]复制到TR1[]
k++;
i++;
}
while (j<=n){
TR1[k]=arr[j]; 将剩余的arr[j,n]复制到TR1[]
k++;
j++;
}
}
}
时间复杂度O(nlogn)
7.快速排序
快速排序的基本思想是任取待排序序列的一个元素作为中心元素(可以用第一个,最后一个,也可以是中间任何一个),习惯将其称为pivot,枢轴元素; 将所有比枢轴元素小的放在其左边; 将所有比它大的放在其右边; 形成左右两个子表; 然后对左右两个子表再按照前面的算法进行排序,直到每个子表的元素只剩下一个。
import java.util.Arrays;
public class quickSort {
//快速排序
public static void main(String[] args) {
int[] arr={
50,10,90,30,70,40,80,60,20};
QSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void QSort(int[] arr,int low,int high){
int pivot;
if (low<high){
pivot=Partition(arr,low,high);
QSort(arr,low,pivot-1);
QSort(arr,pivot+1,high);
}
}
public static int Partition(int[] arr,int low,int high){
int pivotKey=arr[low];
while (low<high){
while(low<high&&arr[high]>=pivotKey){
high--;
}
swap(arr,high,low); //将比枢轴元素小的交换到低端
while (low<high&&arr[low]<pivotKey){
low++;
}
swap(arr,low,high);
}
return low; //返回枢轴元素所在的位置
}
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
最优时间复杂度:O(nlogn)
最坏时间复杂度:O(n^2)
平均时间复杂度:O(nlogn)