基础排序
冒泡排序
- 冒泡排序就是从前往后比较元素,如果比当前元素比后面的元素大就交换两个元素,这样较大的值就一次次冒泡,一直冒泡到了后面位置
- 优化:在一次排序中如果没有产生交换就说明已经排好了序,就不用继续循环了
图解
复杂度和稳定性
- 时间复杂度:O(n)~O(n2)
- 空间复杂度:O(1)
- 稳定的
代码
public static void bubbleSort(int[] arr){
if (arr == null){
return;
}
boolean flag = false;
for (int i = arr.length - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = true;
}
}
if (!flag){
break;
}
flag = false;
}
}
选择排序
- 依次从j到n-1处选择一个最小的值放到j处
图解
复杂度和稳定性
- 时间复杂度O(n2)
- 空间复杂度O(1)
- 不稳定的:涉及到交换位置(如5 6 5 3,5与3 换位置之后就缺失了稳定性)
代码
public static void selectSort(int[] arr){
if (arr == null) {
return;
}
for (int i = 0; i < arr.length-1; i++) {
int minIndex = i;
int min = arr[i];
for (int j = i; j < arr.length; j++) {
if (min > arr[j]) {
min = arr[j];
minIndex = j;
}
}
int temp = arr[i];
arr[i] = min;
arr[minIndex] = temp;
}
}
插入排序
- 将一个数组分为有序表和无序表,开始时有序表中的元素为1,然后遍历无序表依次插入至有序表
图解
复杂度与稳定性
时间复杂度:O(n) ~ O(n2)
空间复杂度:O(1)
稳定性:稳定的
代码
public static void insertSort(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length - 1; i++) {
int j = i + 1;
while (j >= 0 && arr[j - 1] > arr[j]) {
arr[j] = arr[j - 1];
j--;
}
}
}
高级排序
希尔排序
- 希尔排序也是一种插入排序,是一种缩小增量排序
- 每次按照一定增量将数组进行分组,对每组进行插入排序
- 将增量不断减小并重复执行2,直至增量减小为1,这时整个数组被分为一组并进行最后一次重排
图解
复杂度与稳定性
- 时间复杂度:O(nlogn)
- 空间复杂度:O(1)
- 稳定性:不稳定
代码
public static void shellSort(int[] arr){
if (arr == null) {
return;
}
for (int gap = arr.length/2; gap > 0; gap >>= 1){
for (int i = gap; i < arr.length; i++) {
int j = i;
while (j >= gap && arr[j] < arr[j-gap]){
arr[j] = arr[j-gap];
j -= gap;
}
arr[j] = arr[i];
}
}
}
归并排序
- 先将数组进行拆分,然后进行合并,合并时进行重排
- 需要利用到辅助数组来暂存合并后的结果
图解
复杂度与稳定性
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n)
- 稳定的
代码
public static void mergeSort(int arr[]){
if (arr == null) {
return;
}
int[] ass = new int[arr.length];
mergeSort(arr,0,arr.length-1,ass);
}
private static void mergeSort(int arr[], int lo, int high, int[] ass){
if (lo >= high){
return;
}
int mid = lo + (high - lo)/2;
mergeSort(arr,lo,mid,ass);
mergeSort(arr,mid+1,high,ass);
merge(arr,lo,high,ass);
}
private static void merge(int[] arr, int lo, int high, int[] ass){
int mid = lo + (high - lo)/2;
int idx1 = lo;
int idx2 = mid+1;
int idxass = lo;
while (idx1 <= mid && idx2 <= high){
if (arr[idx1] < arr[idx2]){
ass[idxass++] = arr[idx1++];
}else {
ass[idxass++] = arr[idx2++];
}
}
while (idx1 <= mid){
ass[idxass++] = arr[idx1++];
}
while (idx2 <= high){
ass[idxass++] = arr[idx2++];
}
for (int i = lo; i <= high; i++) {
arr[i] = ass[i];
}
}
快速排序
- 是对冒泡排序的改进,选择一个基数,将数组分成两部分,左边部分都比基数小,右边部分都比基数大
- 对左右部分分别都执行1,直至为最小粒度
图解
复杂度和稳定性
- 时间复杂度:O(n2)~O(nlogn)
- 空间复杂度:O(1)
- 稳定性:不稳定的
代码
public static void quickSort(int[] arr){
if (arr == null){
return;
}
quickSort(arr,0,arr.length-1);
}
public static void quickSort(int[] arr, int lo, int high){
if (lo >= high) {
return;
}
int index = getIndex(arr,lo,high);
quickSort(arr,lo,index-1);
quickSort(arr,index+1,high);
}
public static int getIndex(int[] arr, int lo, int high){
int left = lo;
int base = arr[lo];
int right = high + 1;
while (left < right){
while (right > left && arr[--right] > base){}
while (left < right && arr[++left] < base){}
int temp = arr[right];
arr[right] = arr[left];
arr[left] = temp;
}
arr[lo] = arr[right];
arr[right] = base;
return right;
}
堆排序
- 构建一个堆
- 容易想到的是之间创建一个长度为
arr.length+1
的数组然后将其一个个添加到heap
数组中的1~heap.length-1
位置 - 可以直接将
arr
拷贝到heap
数组中的1~heap.length-1
位置,只需要对heap.length/2~1
的元素依次进行下沉(sink)即可一定要是从右往左扫描,也就是从倒数第二行的最末位置开始下沉,叶子节点不用下沉
- 容易想到的是之间创建一个长度为
- 利用堆的特性,依次弹出堆顶的顺序就是排序结果
- 弹堆顶:用最后一个元素代替堆顶,size-1,并进行下沉(sink)
图解
略
复杂度和稳定性
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n) O(1):不用辅助数组下面给出的代码是使用了辅助数组
- 稳定性:不稳定
代码
public static void sink(int[] heap, int position, int size) {
int left = position * 2;
int right = position * 2 + 1;
if (left <= size) {
int min = Integer.MAX_VALUE;
int minIndex = left;
if (right <= size) {
min = heap[right];
minIndex = right;
}
if (heap[left] < min) {
min = heap[left];
minIndex = left;
}
if (min < heap[position]) {
heap[minIndex] = heap[position];
heap[position] = min;
sink(heap, minIndex,size);
}else {
return;
}
}
}
private static int[] buildHeap(int[] arr) {
if (arr == null || arr.length <= 0) {
return null;
}
int[] heap = new int[arr.length + 1];
System.arraycopy(arr, 0, heap, 1, arr.length);
for (int i = heap.length/2; i >= 1; i--) {
sink(heap, i,heap.length-1);
}
return heap;
}
public static void heapSort(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
int[] heap = buildHeap(arr);
ArrayList<Integer> result = new ArrayList<>(heap.length - 1);
int size = heap.length - 1;
while (size > 0) {
int position = 1;
result.add(heap[position]);
heap[position] = heap[size];
heap[size--] = 0;
int left;
int right;
int minIndex;
while ((left = position * 2) <= size) {
right = position * 2 + 1;
if (right <= size) {
minIndex = heap[left] < heap[right] ? left : right;
} else {
minIndex = left;
}
int min = heap[minIndex];
if (heap[position] > min) {
heap[minIndex] = heap[position];
heap[position] = min;
}
position <<= 1;
}
}
System.out.println(result);
}