堆排序
和直接选择排序很像,每次去一个最大值,放到数组的最后。
实现:1. 先针对整个数组建堆;2.循环取堆顶最大值,放到最后面
3调整堆
时间复杂度O(NlogN)
空间复杂度O(1)
不稳定
public static void heapSort(int[] array) {
createHeap(array); //1.创建堆
for (int i = 0; i < array.length; i++) {
//2.循环取最大
//区间分成两部分,待排序区间[0,array.length-i)
// 已排序区间[array.length-i,array.length)
swap(array,0,array.length-i-1);
shiftDown(array,array.length-i-1,0);
}
}
private static void createHeap(int[] array) {
//从最后一个非叶子结点,开始出发,从后往前向下调整
for (int i = (array.length-1-1)/2; i >= 0; i--) {
shiftDown(array,array.length,i);
}
}
//下沉调整
private static void shiftDown(int[] array, int size, int index) {
int parent = index;
int child = 2 * parent + 1;
while (child < size) {
if(child + 1 <size && array[child + 1] >array[child]) {
child = child + 1;
}
if(array[child] > array[parent]) {
swap(array,parent,child);
} else {
break;
}
parent = child;
child = 2 * parent + 1;
}
}
冒泡排序**
实现:每次找出待排序区间的最大值或最小值,相邻元素比较,从前往后比较或从后往前比较
时间复杂度O( n^2)
空间复杂度O(1)
不稳定
public static void bubbleSort(int[] array) {
for (int bound = 0;bound < array.length; bound++) {
for (int cur =array.length-1; cur >= bound; cur--) {
if(array[cur-1] > array[cur]){
swap(array,cur-1,cur);
}
}
}
}
快速排序***
实现:先选择一个基准值
例如: 9 5 2 7 3 6 8 9 4
选最后一个元素4为基准值,从前往后找到比4大的第一个元素,从后往前找到比基准值小的第一个元素,交换这两个元素,若没有找到,就将基准值和找到的那个元素交换(重合时)
核心思路:借助递归
时间复杂度O(n^2) 平均O(NlogN)
空间复杂度O(n) 平均O(logN)
public static void quickSort(int[] array) {
quickSortHeaper(array,0,array.length-1);
//参数的含义表示针对数组中的那段区间进行快速排序[0,array.length-1]
}
private static void quickSortHeaper(int[] array,int left,int right){
//只有一个元素
if (left >= right) {
return;
}
int index = Partition(array,left,right);
quickSortHeaper(array, left, index-1);
quickSortHeaper(array, index + 1, right);
}
private static int Partition(int[] array,int left, int right) {
int baseIndex = right;
int baseValue = array[baseIndex]; //取出基准值
while (left < right) {
while (left < right && array[left] <= baseValue) {
left ++;
}
while(left <right && array[left] >= baseValue) {
right--;
}
swap(array,left,right);
}
swap(array,left,baseIndex);//重合位置和基准值交换
return left;
}
//快速排序(非递归)
public static void quickSortByLoop(int[] array) {
//创建一个栈,存的是待处理区间的下标
Stack<Integer> stack = new Stack<>();
stack.push(array.length-1);//初始情况下待处理区间就是整个数组
stack.push(0);
//取栈顶元素,栈顶元素就是我们要处理的区间
while(!stack.isEmpty()) {
int left = stack.pop();
int right = stack.pop();
if(left >= right) {
continue;
}
//4.对当前待处理区间进行整理
int index = Partition(array,left,right);
stack.push(index - 1);
stack.push(left);
stack.push(right);
stack.push(index + 1);
}
}
快速排序的优化:
1.取基准值 :三元素取中
2.如果递归深度到达一定的层次之后,就不在继续递归,对待排区间使用其他排序方法
3.如果当前待排序区间较小,之间使用插排即可
归并排序
归并两个有序的链表,变成一个有序的链表
时间复杂度O(NlogN)
空间复杂度O(N)
//7.归并排序
public static void mergeSort(int[] array) {
//后两个参数表示要进行归并的区间[0,array.length)
mergeSortHelper(array,0,array.length);
}
private static void mergeSortHelper(int[] array, int left, int right) {
//空区间或只有一个元素,都不需要进行归并
if(left == right || left > right || right - left == 1) {
return;
}
int mid = (left + right) /2;
mergeSortHelper(array,left,mid);
mergeSortHelper(array,mid,right);
merge(array,left,mid,right);
}
private static void merge(int[] array, int left, int mid, int right) {
//创建一段临时空间辅助,长度应是两个待排序区间之和
int length = right - left;
int[] output = new int[length];
int outputIndx = 0;//保存output中末尾元素的下标
int i = left;
int j = mid;
while(i < mid && j < right) {
if(array[i] <= array[j]) {
output[outputIndx++] = array[i++];
} else {
output[outputIndx++] =array[j++];
}
//循环完后,把剩下的一方直接拷贝到output中
while (i < mid) {
output[outputIndx++] = array[i++];
}
while (j < right) {
output[outputIndx++] = array[j++];
}
//最后,把output中的元素拷贝到原来的区间
for (int k = 0; k < length; k++) {
array[left - k] = output[k];
}
}
}
//非递归归并排序
public static void mergeSortByLoop(int[] array) {
for (int gap= 1; gap < array.length; gap *= 2) {
for (int i= 0; i < array.length; i += 2 * gap) {
int beg = i;
int mid = i + gap;
int end = i + 2*gap;
if(mid > array.length) {
mid = array.length;
}
if (end > array.length) {
end = array.length;
}
merge(array,beg,mid,end);
}
}
}
}