一、直接插入排序
/**
* 直接插入排序,时间复杂度最好为O(N),最坏为O(N^2),空间复杂度为O(1)
* 数组里的哪一个值大就把该值赋给arr[j+1]
* 数据越有序,时间效率越高
* 属于稳定排序
* @param arr
*/
public void insertSort1(int[] arr){
for (int i = 1; i < arr.length; i++) {
int val = arr[i];
int j = i-1;
//谁大把谁赋值给arr[j+1];
for (; j >= 0 && arr[j]>val; j--) {
arr[j+1] = arr[j];
}
arr[j+1] = val;
}
}
二、希尔排序
/**
* 希尔排序,时间复杂度最好为O(N),最坏是O(N^2),空间复杂度为O(1)
* 循环分组,当gap>1时候,使用直接插入排序来使数组趋于有序,循环结束之后在使用一次直接插入排序完成这次希尔排序
* 稳定性:这是不稳定排序
* @param arr
*/
public void shellSort(int[] arr){
int gap = arr.length;
while (gap>1){
inserSorth(arr,gap);
gap = (gap/3)+1;
}
inserSorth(arr,gap);
}
private void inserSorth(int[] arr,int gap){
for (int i = 1; i < arr.length; i++) {
int val = arr[i];
int j = i -gap;
for (; j >= 0 && arr[j] > val; j -= gap) {
arr[j+gap] = arr[j];
}
arr[j+gap] = val;
}
}
三、选择排序
/**
* 选择排序,时间复杂度最好为O(N^2),空间复杂度为O(1)
* 从无序区间选出最大的值放到有序区间,知道无序区间走完则循环结束,排序完成
* 稳定性:不稳定
* @param arr
*/
public void selectSort(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
int max = 0;
for (int j = 1; j < arr.length -i; j++) {
if(arr[j] > arr[max]){
max = j;
}
}
int tmp = arr[max];
arr[max] = arr[arr.length -i -1];
arr[arr.length -i -1] = tmp;
}
}
四、堆排序
/**
* 堆排序,时间复杂度,最好和最坏都为O(N*logN);空间复杂度为O(1).
* 向下调整:首先计算index下标左孩子下标left,判断下标left是否小于堆中元素个数,小于则进入循环,
* 然后判断index又孩子下标是否小于size,在比较左右孩子下标所对应的值,把值大的下表给MAX;
* 然后判断arr[max]与arr[index]的大小关系,后者大则跳出循环,否则将两者的值调换,然后让index指向MAX,left指向2*index+1;
* 稳定性:不稳定
* @param arr
*/
public void heapSort(int[] arr){
createHeap(arr);
for (int i = 0; i < arr.length-1; i++) {
swap(arr,arr.length-i-1,0);
shiftDown(arr,arr.length-i-1,0);
}
}
public void swap(int[] arr,int i,int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
//建一个小堆
public void createHeap(int[] arr){
for (int i = (arr.length-1)/2; i>= 0; i--) {
shiftDown(arr,arr.length,i);
}
}
public void shiftDown(int[] arr,int size,int index){
int left = 2*index +1;
while(left<size){
int max = left;
int right = 2*index+2;
if(right < size){
if(arr[left] < arr[right]){
max = right;
}
}
if(arr[index] >= arr[max]){
break;
}
int tmp = arr[index];
arr[index] = arr[max];
arr[max] = tmp;
index = max;
left = 2*index +1;
}
}
五、冒泡排序
/**
* 冒泡排序:时间复杂度最好和最坏都为O(N^2),空间复杂度为O(1);
* 将最大的值冒泡到数组最后,直到数组走完,排序结束;
* 稳定性:稳定
* @param arr
*/
public void bubbleSort(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j]>arr[j+1]){
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
/**
* 优化冒泡排序:时间复杂度最好为O(N),最坏都为O(N^2),空间复杂度为O(1);
* 在循环过程中加入一个boolean变量来检验排序是否完成;
* 稳定性:稳定
*/
public void optimizeBubbleSort(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
boolean flg = false;
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j]>arr[j+1]){
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
flg = true;
}
}
if (flg == false){
break;
}
}
}
六、快速排序
/**
*
* 快速排序:时间复杂度最好为O(N*logN),最坏为O(N^2),空间复杂度最好为O(logN),最坏为O(N);
* 从待排序区间选择一个数,作为基准值(index);
* Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
* 稳定性:不稳定
* @param arr
*/
public void quickSort(int[] arr) {
quickSortInternal(arr,0,arr.length-1);
}
private void quickSortInternal(int[] arr,int left,int right){
if(left == right){
return;
}
if(left > right){
return;
}
int index = partition(arr,left,right);
quickSortInternal(arr,left,index -1);
quickSortInternal(arr,index +1,right);
}
private int partition(int[] arr, int left, int right){
int i = left;
int j = right;
int value = arr[left];
while (i < j){
while (i<j && arr[j]>=value){
j--;
}
arr[i] = arr[j];
while (i<j && arr[i] <= value){
i++;
}
arr[j] = arr[i];
}
arr[i] = value;
return i;
}
/**
* 快速排序的非递归实现
* 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据。
* 稳定性:不稳定
* @param arr
*/
public void quickSortH(int[] arr) {
Stack<Integer> stack = new Stack<>();
stack.push(arr.length - 1);
stack.push(0);
while (!stack.isEmpty()) {
int left = stack.pop();
int right = stack.pop();
if (left >= right) {
continue;
}
int index = partition(arr, left, right);
stack.push(right);
stack.push(index + 1);
stack.push(index - 1);
stack.push(left);
}
}
七、归并排序
/**
* 归并排序:最好和最坏时间复杂度都为O(N*logN),空间复杂度为O(N);
* 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。
* 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
* 稳定性:稳定
* @param array
*/
public void mergeSort(int[] array) {
for (int i = 1; i < array.length; i = i * 2) {
for (int j = 0; j < array.length; j = j + 2 * i) {
int low = j;
int mid = j + i;
if (mid >= array.length) {
continue;
}
int high = mid + i;
if (high > array.length) {
high = array.length;
}
merge(array, low, mid, high);
}
}
}
private void merge(int[] array, int low, int mid, int high) {
int i = low;
int j = mid;
int length = high - low;
int[] extra = new int[length];
int k = 0;
while (i < mid && j < high) {
if (array[i] <= array[j]) {
extra[k++] = array[i++];
} else {
extra[k++] = array[j++];
}
}
while (i < mid) {
extra[k++] = array[i++];
}
while (j < high) {
extra[k++] = array[j++];
}
for (int t = 0; t < length; t++) {
array[low + t] = extra[t];
}
}