快速排序
基本思想
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序
时空复杂度
快速排序的最坏时间为O(n^2)
平均时间复杂度为O(nlgn)
在初始数组近乎有序的状态下最耗时
/*
* 快速排序
*/
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int key = partition(arr, low, high);
quickSort(arr, key + 1, high);
quickSort(arr, low, key - 1);
}
}
public static int partition(int[] arr, int left, int right) {
int temp;
int key = arr[left];
int low = left, high = right;
while (low < high) {
while (arr[low] <= key) {
low++;
}
while (arr[high] > key) {
high--;
}
if (low < high) {
temp = arr[low];
arr[low] = arr[high];
arr[high] = temp;
}
}
arr[left] = arr[high];
arr[high] = key;
return high;
}
冒泡排序
基本原理
相邻的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,这样一趟过去后,最大或最小的数字被交换到了最后一位,然后再从头开始进行两两比较交换,直到排序结束
时空复杂度
冒泡排序最好的时间复杂度为O(n)
最坏时间复杂度为O(n^2)
平均时间复杂度为O(n^2)。
/*
* 改进型冒泡排序
* 时间复杂度最好为O(n),最差为O(n2)
*/
public static void bubbleSort(int[] arr) {
int i,temp,j;
int pass = arr.length-1;
boolean flag = true;
//相邻进行比较
for(i=0;i<arr.length&&flag;i++){
flag = false;
for(j=0;j<pass;j++){
if (arr[j]>arr[j+1]) {
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = true;
}
}
pass--;
}
}
选择排序
基本原理
在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
时空复杂度
平均时间复杂度为O(n^2)。
/*
* 选择排序
* 时间复杂度为O(n2) 空间复杂度为O(1)
*/
public static void selectSort(int[] arr) {
int i,j,min,temp;
//寻找未排序数组的最小值
for(i=0;i<arr.length;i++){
min = i;
for(j=i+1;j<arr.length;j++){
if (arr[min]>arr[j]) {
min = j;
}
}
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
插入排序
基本原理
将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
时空复杂度
最好的时间复杂度为O(n)
最坏时间复杂度为O(n^2)
平均时间复杂度为O(n^2)。
/*
* 插入排序
*/
public static void InsertSort(int[] arr) {
int i,j,temp;
for (i = 0;i<arr.length;i++) {
temp = arr[i];
System.out.println(temp);
for(j=i-1;j>=0;j--){
if (temp<arr[j]) {
arr[j+1] = arr[j];
}else {
break;
}
}
arr[j+1] = temp;
}
}
归并排序
基本原理
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
时空复杂度
平均时间复杂度为O(nlogn)。
/*
* 归并排序
*/
public static void mergeSort(int[] arr,int low,int high) {
int i=low,j=high;
int mid;
if (i<j) {
mid = (i+j)/2;
mergeSort(arr,low,mid);
mergeSort(arr, mid+1, high);
merge(arr, low, mid,high);
}
}
private static void merge(int[] arr,int low,int mid,int high) {
int[] temp = new int[high-low+1];
int i,j,k;
for(i=low,j = mid+1,k=0;i<=mid&&j<=high;){
if(arr[i]<=arr[j]){
temp[k] = arr[i];
i++;
k++;
}else {
temp[k] = arr[j];
j++;
k++;
}
}
while(i<=mid){
temp[k] = arr[i];
i++;
k++;
}
while(j<=high){
temp[k] = arr[j];
j++;
k++;
}
for(i=low,k=0;i<=high;i++,k++){
arr[i] = temp[k];
}
}
希尔排序
基本原理
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
时空复杂度
希尔排序的时间复杂度与增量序列的选取有关
/*
* 希尔排序
*/
public static void shellSort(int[] arr) {
int step = arr.length/2;
for(;step>=1;step/=2){
for(int i=0;i<step;i++){
for(int j=i+step;j<arr.length;j+=step){
if (arr[j]<arr[j-step]) {
int temp = arr[j];
int k = j-step;
for(;k>=0&&arr[k]>temp;k-=step){
arr[k+step] = arr[k];
}
arr[k+step] = temp;
}
}
}
}
}
堆排序
基本原理
初始时把要排序的n个数的序列看作是一棵顺序存储的二叉树(一维数组存储二叉树),调整它们的存储序,使之成为一个堆,得到n 个元素中最小(或最大)的元素,这时堆的根节点的数最小(或者最大)。将堆顶元素跟堆中最后一个元素交换,然后对前面(n-1)个元素重新调整使之成为堆,得到n 个元素中次小(或次大)的元素。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。称这个过程为堆排序。
时空复杂度
平均时间复杂度为O(nlogn)。
/*
* 堆排序
*/
public static void heapSort(int[] arr) {
// 从最后一个非叶子节点建立初始堆
for (int i = arr.length / 2; i >= 0; i--) {
buildHeap(arr, i, arr.length);
}
// 进行n-1次循环,完成排序
for (int i = arr.length - 1; i > 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
// 重建堆
buildHeap(arr, 0, i);
}
}
private static void buildHeap(int[] arr,int parent,int length) {
int temp = arr[parent];
int child = 2 * parent + 1;
while (child < length) {
if (child + 1 < length && arr[child] < arr[child + 1]) {
child++;
}
if (temp >= arr[child])
break;
arr[parent] = arr[child];
arr[child] = temp;
// 选取孩子结点的左孩子结点,继续向下建堆
parent = child;
child = 2 * child + 1;
}
arr[parent] = temp;
}