对数阶排序算法

定义交换函数

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值