选择排序:时间复杂度;O(N^2),空间复杂度:O(1),非稳定,原地排序
描述:首先,找到数组中最小的元素(一般指定数组的第一个元素就是最小的),然后,将他与数组的第一个元素进行比较,如果比它小,则交换位置。依次比较到数组的最后一个元素,找出整个数组的最小值。后面重复,找出第二小的值
代码:
public static int[] selectSort(int[] n){
for(int i=0;i<n.length-1;i++){
for(int j=i+1;j<n.length;j++){
if(n[i]>=n[j]){
int temp=n[i];
n[i]=n[j];
n[j]=temp;
}
}
}
return n;
}在这里插入代码片
插入排序:时间复杂度:O(N^2),空间复杂度:O(1) 稳定,原地排序
描述:插入排序的原理是默认前面的元素都是已经排序好的,然后从后面逐个读取插入到前面排序好的合适的位置,就相当于打扑克的时候每获取一张牌的时候就插入到合适的位置一样。插入排序可以分为两种,一种是直接插入还一种是二分法插入,直接插入的原理比较简单,就是往前逐个查找直到找到合适的位置然后插入,二分法插入是先折半查找,找到合适的位置然后再插入。
代码:
public static int[] insertSort(int[] n){
if(n==null||n.length<2) return n;
for(int i=1;i<n.length;i++){
int temp=n[i];
int k=i-1;
while(k>=0&&n[k]>temp)
k--;
//腾出位置插进去,要查的位置是k+1
for(int j=i;j>k+1;j--)
n[j]=n[j-1];
//插进去
n[k+1]=temp;
}
return n;
}在这里插入代码片
冒泡排序:时间复杂度:O(N^2),空间复杂度:O(1),稳定,原地排序
描述:把第一个元素与第二个元素比较,如果第一个比第二个大,则交换位置,接着比较第二个与第三个,反正总是相邻位置的元素进行比较,循环一次下来,最右边的元素是最大值,除去最右的元素,对剩余的元素做同样的操作。
代码:
public static int[] bubbleSort(int[] n){
if(n==null||n.length<2) return n;
for(int i=0;i<n.length-1;i++){
boolean flag=true;
for(int j=0;j<n.length-1-i;j++){
if(n[j]>n[j+1]){
flag=false;
int t=n[j];
n[j]=n[j+1];
n[j+1]=t;
}
}
//一趟下来是否发生位置交换
if(false)
break;
}
return n;
}
快速排序(Quick Sort):是对冒泡排序的一种改进方法,在冒泡排序中,进行元素的比较和交换是在相邻元素之间进行的,元素每次交换只能移动一个位置,所以比较次数和移动次数较多,效率相对较低。而在快速排序中,元素的比较和交换是从两端向中间进行的,较大的元素一轮就能够交换到后面的位置,而较小的元素一轮就能交换到前面的位置,元素每次移动的距离较远,所以比较次数和移动次数较少,y速度较快,故称为“快速排序”。
快速排序的基本思想是:
1.在待排序的元素任取一个元素作为基准(通常选第一个元素,但最的选择方法是从待排序元素中随机选取一个作为基准),称为基准元素;
2.将待排序的元素进行分区,比基准元素大的元素放在它的右边,比其小的放在它的左边;
3.对左右两个分区重复以上步骤直到所有元素都是有序的
代码:时间复杂度:O(nlogn),空间复杂度:O(logn),非稳定,原地排序
public int[] MySort (int[] arr) {
return quickSort(arr,0,arr.length-1);
}
private int[] quickSort(int[] arr, int L, int R) {
if(L>=R) return arr;
int left=L,right=R;
int a=arr[left];
while(left<right){
while(left<right&&arr[right]>=a)
right--;
if (left<right){
arr[left]=arr[right];
left++;
}
while(left<right&&arr[left]<a)
left++;
if (left<right){
arr[right]=arr[left];
right--;
}
if (left>=right){
arr[left]=a;
}
}
quickSort(arr,L,right-1);
quickSort(arr,right+1,R);
return arr;
}
归并排序:
描述:归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。
代码:
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 将给定数组排序
* @param arr int整型一维数组 待排序的数组
* @return int整型一维数组
*/
public int[] MySort (int[] arr) {
mergeSort(arr,0,arr.length-1);
return arr;
}
public void mergeSort(int[] arr,int l,int r){
if(l==r){
return;
}
int mid = l+((r-l)>>1); //中点位置,即(l+r)/2
mergeSort(arr,l,mid);
mergeSort(arr,mid+1,r);
merge(arr,l,mid,r);
}
public void merge(int[] arr,int l,int mid,int r){
int [] help= new int[r-l+1]; //辅助数组
int i=0;
int p1=l; //左半数组的下标
int p2=mid+1; //右半数组的下标
//判断是否越界
while(p1<=mid && p2<=r){
help[i++]=arr[p1]<arr[p2] ? arr[p1++] : arr[p2++];
}
//p1没有越界,说明p2越界了,将左边剩余元素拷贝到辅助数组
while(p1<=mid){
help[i++]=arr[p1++];
}
//p2没有越界,说明p1越界了
while(p2<=r){
help[i++]=arr[p2++];
}
//将辅助数组元素拷贝会原数组
for(i=0;i<help.length;i++){
arr[l+i]=help[i];
}
}
}
非递归式的:
public class MergeSort {
// 非递归式的归并排序
public static int[] mergeSort(int[] arr){
int n = arr.length;
// 子数组的大小分别为1,2,4,8...
// 刚开始合并的数组大小是1,接着是2,接着4....
for (int i = 1; i < n; i += i) {
//进行数组进行划分
int left = 0;
int mid = left + i - 1;
int right = mid + i;
//进行合并,对数组大小为 i 的数组进行两两合并
while (right < n) {
// 合并函数和递归式的合并函数一样
merge(arr, left, mid, right);
left = right + 1;
mid = left + i - 1;
right = mid + i;
}
// 还有一些被遗漏的数组没合并,千万别忘了
// 因为不可能每个字数组的大小都刚好为 i
if (left < n && mid < n) {
merge(arr, left, mid, n - 1);
}
}
return arr;
}
}
堆排序:可以理解为二叉树排序,这里的堆分为两种,一种是大顶堆,一种是小顶堆,我们所有的排序方法都以升序为主,其实倒序原理也都差不多,所以这里我们主要分析的是大顶堆。大顶堆就是根节点不小于他的两个子节点。
代码:
public int[] MySort(int[] arr) {
int length = arr.length;
buildMaxHeap(arr, length);
for (int i = 0; i < length; i++) {
swap(arr, 0, length - 1 - i);
maxHeapfy(arr, 0, length - i - 1);
}
return arr;
}
private void maxHeapfy(int[] arr, int i, int heapSize) {
int left = i * 2 + 1;
int right = i * 2 + 2;
int largest = i;
if (left < heapSize && arr[left] > arr[largest]) {
largest = left;
}
if (right < heapSize && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {//把最大值给父节点
swap(arr, largest, i);
maxHeapfy(arr, largest, heapSize);
}
}
private void buildMaxHeap(int[] array, int heapSize) {
//从最后一个非叶子节点开始循环
for (int i = (heapSize - 2) >> 1; i >= 0; i--) {
maxHeapfy(array, i, heapSize);
}
}
public void swap(int[] A, int i, int j) {
if (i != j) {
A[i] ^= A[j];
A[j] ^= A[i];
A[i] ^= A[j];
}
}```