总结并不全面,会在复习过程中,动态更新
排序算法总结
1.快速排序
import java.util.*;
public class Solution {
public int[] Sort (int[] arr) {
// write code here
quickSort(arr,0,arr.length-1);//快速排序入口
return arr;
}
public void quickSort(int[] arr,int left,int right){
if(left<right){
int mid=findpar(arr,left,right);//得到分割位的最终位置
quickSort(arr,left,mid-1); //快排左部分
quickSort(arr,mid+1,right); //快排右部分
}
}
public int findpar(int[] arr,int left,int right){
int par=arr[left]; //得到分割位,且left下标为坑位1
while(left<right){
//得到分割位右边的比分割位小的数的下标,为right
while(left<right&&par<=arr[right]){
right--;
}
//将其放入坑位1,即移到分割位左边
//此时right为坑位2
arr[left]=arr[right];
//得到分割位左边的比分割位大的数的下标,为left
while(left<right&&par>=arr[left]){
left++;
}
//将其放入坑位2,即移到分割位右边
arr[right]=arr[left];
}
//如此反复,left==right
//此时,left左边都<=par,right右边都>=par
//left下标下存入par,并返回left
arr[left]=par;
return left;
}
}
2.冒泡排序
*/
public class BubbleSort {
public static void sort(int[] array) {
if (array == null || array.length == 0) {
return;
}
int length = array.length;
//外层:需要length-1次循环比较
for (int i = 0; i < length - 1; i++) {
//内层:每次循环需要两两比较的次数,每次比较后,都会将当前最大的数放到最后位置,所以每次比较次数递减一次
for (int j = 0; j < length - 1 - i; j++) {
if (array[j] > array[j+1]) {
//交换数组array的j和j+1位置的数据
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
}
}
3.选择排序
public class SelectSort {
public static void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int min = i;
for (int j = i+1; j < arr.length; j ++) { //选出之后待排序中值最小的位置
if (arr[j] < arr[min]) {
min = j;
}
}
if (min != i) {
arr[min] = arr[i] + arr[min];
arr[i] = arr[min] - arr[i];
arr[min] = arr[min] - arr[i];
}
}
}
4.归并排序
public static int[] mergingSort(int[] arr){
if(arr.length <= 1) return arr;
int num = arr.length >> 1;
int[] leftArr = Arrays.copyOfRange(arr, 0, num);
int[] rightArr = Arrays.copyOfRange(arr, num, arr.length);
return mergeTwoArray(mergingSort(leftArr), mergingSort(rightArr)); //不断拆分为最小单元,再排序合并
}
private static int[] mergeTwoArray(int[] arr1, int[] arr2){
int i = 0, j = 0, k = 0;
int[] result = new int[arr1.length + arr2.length]; //申请额外的空间存储合并之后的数组
while(i < arr1.length && j < arr2.length){ //选取两个序列中的较小值放入新数组
if(arr1[i] <= arr2[j]){
result[k++] = arr1[i++];
}else{
result[k++] = arr2[j++];
}
}
while(i < arr1.length){ //序列1中多余的元素移入新数组
result[k++] = arr1[i++];
}
while(j < arr2.length){ //序列2中多余的元素移入新数组
result[k++] = arr2[j++];
}
return result;
}
5.堆排序
//大顶堆,升序排序
public static void sort(int []arr){
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
/**
* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
* @param arr
* @param i
* @param length
*/
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//将temp值放到最终的位置
}
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
应用场景
(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
若要求排序稳定,则可选用归并排序。但前面介绍的从单个记录起进行两两归并的排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子序列,然后再两两归并之。因为直接插入排序是稳定 的,所以改进后的归并排序仍是稳定的。