堆排序:
思路:基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。 //不稳定
注意: 排升序要建大堆;排降序要建小堆。
★建大堆的时候,每次是将最后一个元素放在最上面,然后向下调整,将最大的调整到堆顶,然后将堆顶元素归栈,依次循环直到堆里只剩下一个元素。
import java.util.Arrays;
public class HeapSort {
private static void swap(int[] array, int i, int j) {
int t = array[i];
array[i] = array[j];
array[j] = t;
}
public static void heapSort(int[] array) {
createHeapBig(array);
for (int i = 0; i < array.length - 1; i++) {
// 无序 [0, array.length - i)
// 交换 array[0], array[length - i - 1]
// 无序 [0, array.length - i - 1)
// 无序长度 array.length - i - 1
// 下标 0 进行向下调整
swap(array, 0, array.length - i - 1);
shiftDownBig(array, 0, array.length - i - 1);
}
}
private static void createHeapBig(int[] array) { //建大堆
for (int i = (array.length - 2) / 2; i >= 0; i--) {
shiftDownBig(array, i, array.length);
}
}
private static void shiftDownBig(int[] array, int i, int size) { //向下调整
while (2 * i + 1 < size) {
int max = 2 * i + 1;
if (max + 1 < size && array[max+1] > array[max]) {
max = max + 1;
}
if (array[i] >= array[max]) {
return;
}
swap(array, i, max);
i = max;
}
}
public static void main(String[] args){
int[] array={4,5,0,9,6,5,3,1,2,9,3};
heapSort(array);
System.out.println(Arrays.toString(array)); //以数组的形式输出
}
}
快速排序:(partition部分有三种方法)
思路:1. 从待排序区间选择一个数,作为基准值(pivot);
2. Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
3. 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据 //不稳定
import java.util.Arrays;
public class Test0926 {
public static void swap(int[] array,int i,int j){
int t=array[i];
array[i]=array[j];
array[j]=t;
}
public static void quickSort(int[] array,int left,int right){ //left,right指的是下标
quickSortInternal(array,0,array.length-1);
}
private static void quickSortInternal(int[] array,int left,int right){
if(left==right){
return;
}
if(left>right){
return;
}
int pivotIndex=partition(array,left,right);
quickSortInternal(array,left,pivotIndex-1);
quickSortInternal(array,pivotIndex+1,right);
}
private static int partition(int[] array,int left,int right){
int i=left;
int j=right;
int pivot=array[left];
while(i<j){
while(i<j&&array[j]>=pivot){
j--;
}
while(i<j&&array[i]<=pivot){
i++;
}
swap(array,i,j);
}
swap(array,i,left);
return i;
}
//挖坑法
private static int partition1(int[] array,int left,int right){
int i=left;
int j=right;
int pivot=array[left];
while(i<j){
while(i<j&&array[j]>=pivot){
j--;
}
array[i]=array[j];
while(i<j&&array[i]<=pivot){
i++;
}
array[j]=array[i];
}
array[i]=pivot;
return i;
}
private static int partition2(int[] array,int left,int right){
int d=left+1;
int pivot=array[left];
for(int i=left+1;i<=right;i++){
if(array[i]<pivot){
swap(array,i,d);
d++;
}
}
swap(array,d-1,left);
return d-1;
}
public static void main(String[] args){
int[] array={4,5,0,9,6,5,3,1,2,9,3};
quickSort(array,0,9);
System.out.println(Arrays.toString(array)); //以数组的形式输出
}
}
归并排序:
思路:将一个数组分为两部分,对组内的数进行拆分排序,再合并,直到组内的数都排好序为止,采用的是分治的思想。//稳定
import java.util.Arrays;
public class Test0928 {
public static void mergeSort(int[] array){
mergeSortInternal(array,0,array.length);
}
private static void mergeSortInternal(int[] array,int low,int high){
if(low>=high-1){ //考虑是否溢出
return;
}
int mid=(low+high)/2;
mergeSortInternal(array,low,mid);
mergeSortInternal(array,mid,high);
merge(array,low,mid,high);
}
private static 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){ //此时,将数组从mid处分为两个区间,下标分别为i,j
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];
}
}
public static void main(String[] args){
int[] array={4,5,0,9,6,5,3,1,2,9,3};
mergeSort1(array);
System.out.println(Arrays.toString(array)); //按数组的方式打印
}
}
运行结果: