常见排序算法
插入排序:直接插入排序、希尔排序
选择排序:选择排序、堆排序
交换排序:冒泡排序、快速排序
归并排序:归并排序
插入排序:需要从前往后进行扫描,扫描到的每个数都需要和前面的所有数进行比较,然后把这个数放在合适的位置。
时间复杂度:最优全部排好了O(n),最差情况全部进行排序O(n^2)
代码实现:
public class 直接插入排序 {
public static void main(String[] args) {
int [] arr = {38,65,97,76,13,27,49};
arr = insertionSort(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] insertionSort(int[] arr){
int n = arr.length;
for(int i =1;i<n;i++){
int current = arr[i];
int j = i-1;
while(j>=0 && arr[j] > current){
arr[j+1]= arr[j];
j--;
}
arr[j+1] = current;
}
return arr;
}
}
希尔排序:有一个长度为N的数组a,选定一个小于N的整数,然后将数组a拆分,从第一个元素开始将第一个元素和第N+N/a进行比较,然后交换顺序,然后再对该序列进行一次插入排序,然后在选取比上一个增量小的整数作为第二增量,直到递减为1。
相对于直接插入排序,更快些:因为通过大步移动和局部排序,将时间复杂度有了进一步提升
时间复杂度:介于O(nlongn)和O(n^2)之间,做到了对直接插入排序的优化
代码实现:
public class 希尔排序 {
public static void main(String[] args) {
int [] arr = {38,65,97,76,13,27,49};
arr = shellSort(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] shellSort(int[] arr){
int n = arr.length;
for(int gap = n/2;gap>0;gap/=2){
for(int i = gap;i<n;i++){
int current = arr[i];
int j = i-gap;
while(j>=0 && arr[j] > current){
arr[j+gap] = arr[j];
j-= gap;
}
arr[j+=gap] = current;
}
}
return arr;
}
}
选择排序:每次从待排序的中选择最小值,然后和序列起始位置进行交换,直到全部待排序数组排序完
时间复杂度:最坏最好情况都是O(N^2)
代码实现:
public class 选择排序 {
public static void main(String[] args) {
int[] arr = {10,9,8,7,6,5,1,3,4};
arr = selectSort(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] selectSort(int[] arr){
int n = arr.length;
for(int i = 0;i<n-1;i++){
int min = i;
for(int j = i+1;j<n;j++){
if(arr[j] < arr[min]){
min = j;
}
}
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
return arr;
}
}
堆排序:分为大根堆和小根堆,根是对于根节点来说的,大根堆是正序,小根堆是逆序
如图演示大顶堆构建,首先创建大顶堆堆,然后通过向上调整算法去实现大顶堆
实现流程:通过向下调整算法和向上调整算法来分别实现构建小堆和键大堆
时间复杂度:建堆的时间复杂度O(N),向上/向下调整算法的时间复杂度是O(log2N),所以时间复杂度是O(N*log2N)
大顶堆代码实现:
public class 堆排序 {
//构建大顶堆
//然后调整大顶堆
//然后交换首位顺序即可
public static void main(String[] args) {
int [] arr = {38,65,97,76,13,27,49};
arr = heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] heapSort(int arr[]){
int n = arr.length;
buildMaxHeap(arr,n);
for(int i =n-1;i>0;i--){
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
adjustheap(arr,i,0);
}
return arr;
}
public static void adjustheap(int []arr,int n ,int i){
int largest = i;
int left = 2*i+1;
int right= 2*i+2;
if(left<n && arr[left] > arr[largest]){
largest = left;
}
if(right<n && arr[right] > arr[largest]){
largest = right;
}
if(largest != i){
int swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
adjustheap(arr,n,largest);
}
}
public static void buildMaxHeap(int[] arr,int n){
for(int i = n/2-1;i>=0;i--){
adjustheap(arr,n,i);
}
}
}
小顶堆实现代码:
public static int[] headsortmin(int[] arr){
int n = arr.length;
buildminheap(arr,n);
for(int i = n-1;i>0;i--){
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
adujustminheap(arr,i,0);
}
return arr;
}
public static void buildminheap(int[] arr,int n){
for(int i = n/2-1;i>=0;i--){
adujustminheap(arr,n,i);
}
}
public static void adujustminheap(int[] arr,int n,int i){
int min = i;
int left = 2*i+1;
int right = 2*i+2;
if(left<n && arr[left]<arr[min]){
min = left;
}
if(right<n && arr[right]<arr[min]){
min = right;
}
if(min != i){
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
adujustminheap(arr,n,min);
}
}
冒泡排序:通过一次排序,求最大最小值,每次将最大值或者最小值放在符合的对应位置
时间复杂度:最优O(N),最差情况O(N^2)
代码实现:
public class 冒泡排序 {
public static void main(String[] args) {
int[] arr= {8,5,6,4,9,10};
arr = bubbleSort(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] bubbleSort(int[] arr){
int temp;
for(int i =0;i<arr.length-1;i++){
for(int j = 0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
temp= arr[j];
arr[j] = arr[j+1];
arr[j+1] =temp;
}
}
}
return arr;
}
}
快速排序:选出一个基准值,让小于它的元素放在左边,大于它的元素在右边,然后依次再对左边部分进行同样操作,选取一个基准值然后进行分配,直至左边已排好顺序,然后去排序右边
时间复杂度;为O(nlogn),最坏的情况时间复杂度为O(n^2)
代码实现:其实思想就是借助两个指针,也就是代码中for循环中的i和pointer
public class 快速排序 {
//选取基数值,借助两个指针
//选取第一个大于该基数的值,然后去寻找小于该基数的值,然后交换两者位置,然后将指向第一个
//基数值的指针++,继续重复上述操作,当两个指针碰了面,直接交换第一个指针最初指向的值,然后交换两者
public static void main(String[] args) {
int [] arr = {38,65,97,76,13,27,49};
arr = quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static int[] quickSort(int[] arr,int low,int high){
if(low < high){
//先划分子数组的位置
int position = partition(arr,low,high);
quickSort(arr,low,position-1);
quickSort(arr,position+1,high);
}
return arr;
}
public static int partition(int []arr, int low,int high){
//选取中心元素
int pivot = arr[high];
int pointer = low;
//通过i和pointer来当做指针,和基数值进行比较
//将小于的放在左边,大于的放在右边
for(int i =low;i<high;i++){
if(arr[i] <= pivot){
int temp = arr[i];
arr[i] = arr[pointer];
arr[pointer] = temp;
pointer++;
}
}
//然后小于的在一边,arr[pointer]值左边,大于的在pointer右边,当i到high处没有小于arr[high]的值了,
//直接交换arr[pointer] 和arr[high],就可以做到小于的在左边,大于在右边
int temp = arr[pointer];
arr[pointer] = arr[high];
arr[high] =temp;
return pointer;
}
}
归并排序:将序列分成两个长度相等的子序列,然后不断去裂化,当每个子序列只有一个数据时,然后对子序列进行归并,然后依次去不断合并两个子序列
时间复杂度: O(nlogn)
代码实现:和快速排序都是分而治之的思想
public class 归并排序 {
//首先先分组
//然后再合并
public static void main(String[] args) {
int [] arr = {38,65,97,76,13,27,49};
arr = mergeplay(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] mergeplay(int[] nums){
if(nums == null || nums.length == 1){
return nums;
}
nums = mergeSort(nums,0,nums.length-1);
return nums;
}
public static int[] mergeSort(int[] arr,int left,int right){
if(left>= right){
return arr;
}
int mid = left+(right-left)/2;
mergeSort(arr,left,mid);
mergeSort(arr,mid+1,right);
merge(arr,left,mid,right);
return arr;
}
public static void merge(int[] nums,int left,int mid,int right){
int [] temp = new int[right-left+1];
int i = left,j = mid+1 ,k = 0;
while(i<= mid && j<= right){
if(nums[i] <= nums[j]){
temp[k++] = nums[i++];
}else{
temp[k++] = nums[j++];
}
}
while(i <= mid){
temp[k++] = nums[i++];
}
while(j <= right){
temp[k++] = nums[j++];
}
System.arraycopy(temp,0,nums,left,temp.length);
}
}
如果有错误,欢迎指正,创作不易,如果对您有用,留下个赞吧,感谢支持