对数阶排序算法

来源:互联网 发布:mac yosemite lol 编辑:程序博客网 时间:2024/06/05 07:03

定义交换函数

public void swap(int[] arr, int i, int j){    if(i == j) return;    arr[i] = arr[i]^arr[j];    arr[j] = arr[i]^arr[j];    arr[i] = arr[i]^arr[j];}

归并排序
分析:递归分治,不断分割排序合并
用空间换时间
空间复杂度:O(n)
时间复杂度:O(nlogn)共分成logn层,每层要将数组整体元素都访问一遍【想象一下递归二叉树的样子,每层上节点数对应的元素数之和为n】,时间为O(n),因此,总体时间为o(nlogn)
代码:

public void mergeSort(int[] arr, int p, int q){    if(p >= q) return;    int mid = (p+q)/2;    mergeSort(arr, p, mid);    mergeSort(arr, mid+1,q);    merge(arr, p, mid, q);}private void merge(int[] arr, int p, int mid, int q){    int[] temp = new int[arr.length]; //此处将数组设为全局变量,否则每次都要创建一遍。    int i = p, j = mid+1,iter = p;    while(i <= mid && j <= q){        if(arr[i] <= arr[j]) temp[iter++] = arr[i++];        else temp[iter++] = arr[j++];    }    while(i <= mid) temp[iter++] = arr[i++];    while(j <= q) temp[iter++] = arr[j++];    for(int t = p; t <= q; t++) arr[t] = temp[t];}

快速排序
分析:当初始序列整体或者局部有序时,会退化为冒泡排序。
空间复杂度:无需辅助空间(看怎么写,如果用递归,会用栈空间,O(logN))
时间复杂度:最好情况与归并一样。最坏情况为O(N^2)。平均时间O(NlogN)—当序列数字随机分布时,用快排效率最高。
代码(每次以序列最后一个值为 pivot):

public void quickSort(int[] arr, int p, int q){    if(p >= q) return;    int mid = p - 1; //mid为小于pivot值和大于pivot值的分界点    for(int i = p; i < q; i++)        if(arr[i] < arr[q]) swap(arr, ++mid, i);    mid++;    swap(arr, mid, q);    quickSort(arr, p, mid-1);    quickSort(arr, mid+1, q);}

快排与归并的区别

  • 他们都是分治法排序,分治法排序需要两个过程:划分(partition)和合并(merge)。划分策略与合并策略不同
  • 归并的划分部分按一半一半划分没有特殊规则限制,而合并部分需要进行元素比较合并。因此,归并排序的操作重点在merge上。
  • 快排的划分部分是按照比较与pivot的大小来划分,而由于划分后pivot不再参与,合并部分没有任何操作。因此,快排的操作重点在partition上。

堆排
分析:

  • 堆是一种完全二叉树 堆分为大顶堆和小顶堆
    大顶堆:根节点大于两个孩子,且两个子树也是大顶堆
    小顶堆:根节点小于两个孩子,且两个子树也是小顶堆

    感觉就是每个子树的根的值都是其所在子树的局部最优,而整个树的根就是全局最优(最优指的是元素值最大或最小)

  • 堆排序步骤:

    1. 建堆
    2. 交换堆顶元素与最后元素,并调整堆。
      数组中的元素标号对应:父亲i的左右孩子标号为2i+1, 2i+2

时间复杂度:

  • 调整堆的过程由树的高度(层数)决定,因此是O(logN)。

  • 建堆过程简单上界可以这么计算:由于从底向上建堆,时间复杂度应该是调整的节点数x每个节点数下面调整的时间,假设n个节点,就是3n/2xlogN。通过公式推导严格来说建堆接近线性时间O(n)。

  • 堆排序中包含了建堆和调整过程。建堆O(n),调整n-1个节点,因此总时间是O(nlogn)

空间复杂度:如果不用递归用循环,基本不用额外空间。

代码(此处构建大顶堆,堆顶代表无序区的最大元素,不断交换堆顶与无序区的最后一个元素,并调整堆):

public void heapSort(int[] arr){    int start = arr.length/2-1; //建堆时要从最后一个父亲节点开始    for(int i = start; i >=0; i--) heapAdjusted(arr, i, arr.length-1);    for(int len = arr.length-1; len > 0; len--){        swap(arr, 0, len);//将无序区堆顶值与最后一个值交换,也就是说将堆顶值加入至有序区        heapAdjusted(arr, 0, len-1);//由于无序区少了一个数,因此个数减一    }}private void heapAdjusted(int[] arr, int i, int len){//调整堆是一个自上至下的过程    int max = i, left = 2*i+1, right = 2*i+2;    if(left <= len && arr[max] < arr[left]) max = left;    if(right <= len && arr[max] < arr[right]) max = right;    if(max != i){        swap(arr, max, i);        heapAdjusted(arr, max, len);    }} 
0 0
原创粉丝点击