精华内容
下载资源
问答
  • 排序算法比较次数总结
    2022-03-31 11:53:12

    在长度为n的线性表中寻找值最大的元素,最坏的情况需要比较的次数为n-1
    在长度为n的线性表中顺序查找,最坏的情况需要比较的次数为n

    对长度为n的线性表进行快速排序/插入排序/冒泡排序,最坏情况下需要比较的次数为n(n-1)/2

    对于长度为n的有序线性表,在最坏情况下,二分法查找需要比较log2N次

    最坏情况下,有序链表查找的比较次数为n,循环链表中寻找最大项的比较次数为n-1,堆排序比较次数为nlog2N

    希尔排序比较次数为n的r次方(1<r<)。

    更多相关内容
  • 7.2_排序计算次数.cpp

    2019-10-29 19:23:54
    (5)实现堆排序算法。 (6)合并排序算法。 2) 实现提示: 数据输入后,每选择一种算法,把数据拷贝后再排序,保证原始数据不破坏。 2、在上题的基础上增加功能(程序改名另存):增加变量统计每一种排序的...
  • 堆排序时间复杂度的计算过程

    千次阅读 2020-07-14 13:32:50
    本片文章只讲堆排序时间复杂度的计算过程。 package com.westmo1.demo2; import java.util.Arrays; import java.util.Scanner; public class MyDemo3 { public static void main(String[] args) {

    一、代码实现

    关于具体实现过程请点 https://blog.csdn.net/weixin_44324174/article/details/104183349
    本片文章只讲堆排序时间复杂度的计算过程。

    package com.westmo1.demo2;
    import java.util.Arrays;
    import java.util.Scanner;
    public class MyDemo3 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("输入数据");
            int[] ints = new int[7];
            for (int i = 0; i < ints.length; i++) {
                int i1 = scanner.nextInt();
                ints[i]=i1;
            }
            int length=ints.length-1;
            int root=ints.length/2-1;
            for (int i = root; i >=0; i--) {
                BuildHeap(ints, length, i);
            }
            //取值,把根结点元素和最后一个元素交换
            for (int i = 0; i <ints.length; i++) {
                swap(ints,0,length);
                length--;
                BuildHeap(ints,length,0);
            }
            System.out.println(Arrays.toString(ints));
        }
        //建立大根堆
        public static void BuildHeap(int arr[],int length,int root){
            int leftcode=root*2+1;
            int rightcode=root*2+2;
            int max=root;
            if(leftcode<length&&arr[leftcode]>=arr[max]){
                max=leftcode;
            }
            if(rightcode<length&&arr[rightcode]>=arr[max]){
                max=rightcode;
            }
            if (max!=root) {
                swap(arr,max,root);
                //调整完之后,可能会影响到下面的子树,需再次调整
                BuildHeap(arr,length,max);
            }
        }
        private static void swap(int[] arr, int i, int j) {
            int t=arr[i];
            arr[i]=arr[j];
            arr[j]=t;
        }
    }
    

    二、时间复杂度的计算

    注意:这里计算都是以完满二叉树进行计算的。

    1、建堆

    建堆的过程都是从倒数第二层最右边的节点开始,每个节点调整位置花费的时间复杂度是O(1),为了方便后面的计算,统计就说是执行1次;然后是倒数第三层,这一层每个节点也需要执行1次,但是因为调整后会影响到它的后面的节点,所以每个节点还需执行1次(这个次数取决于你的代码怎么写,非常关键),这里非常关键。

    int max=root;
    if(leftcode<length&&arr[leftcode]>=arr[max]){
        max=leftcode;
    }
     if(rightcode<length&&arr[rightcode]>=arr[max]){
        max=rightcode;
    }
    if (max!=root) {
      swap(arr,max,root)
       //调整完之后,可能会影响到下面的子树,需再次调整
       BuildHeap(arr,length,max);
    }
    

    上面的代码是调整节点位置的过程,我们发现,这种代码调整之后的结果是:**父节点最后只和它的左孩子节点或右孩子节点的其中一个发生了交换,**所以倒数第三层每个节点的在调整位置的时候,每个节点只会影响到它的右子树或者左子树的结构中的一个,所以执行1次。如果这里的代码采用的是父节点先和左孩子结点比较交换然后再和右孩子节点比较交换的写法,那它最后时间复杂度计算出来的结果就是nlogn;我们是以最优的算法来计算的。
    我们以三层结构的完满二叉树举例来推导一下计算公式
    在这里插入图片描述
    所以最后推导出来的公式就是:

    S=[2^(k-1)+2^(k-1)*0]+[2^(k-2)+2^(k-2)*1]+[2^(k-3)+2^(k-3)*2]+......+[2^0+2^0*(k-1)]
    化简后得:S=2^(k-1)*1+2^(k-2)*2+2^(k-3)*3+.......+2^0*k;
            S=2^0*k+2^1*(k-1)+......+2^(k-2)*2+2^(k-1)*1;   (1)
    使用等比数列求和中的错位相减法,两边同乘以2,得:
            2S=2^1*k+2^2*(k-1)+......+2^(k-1)*2+2^k*1;      (2)
    (2)-(1)式可得:S=-2^0*k+2^1+2^2+2^3+.......+2^(k-1)+2^k;
    使用等比数列求和公式可得:S=2^(k+1)-k-2;
    

    所以建堆的总执行次数就是:S=2^(k+1)-k-2
    完满二叉树的节点个数是2的整次幂减1,所以2^k-1=节点个数n,所以高度k=log(n+1);
    把k带入S中可得:S=2^(log(n+1)+1)-log(n+1)-2,化简得S=2n-log(n+1);
    所以建堆的时间复杂度为O(n);

    2、取值后重新调整堆

    取值每次取的都是堆顶元素,取完重新调整的次数都是k次,时间复杂度就是也就是logn,而循环要执行n次,所以取值后重新调整堆得时间复杂度就是O(nlogn);

    综上所述,堆排序的时间复杂度就是O(n(logn+1))就是O(nlogn);

    完全都是个人理解,网上搜了好多,自己都没看的太懂,后来自己摸索着搞了搞,哪里有问题还请指正。

    展开全文
  • 堆排序

    万次阅读 多人点赞 2019-06-20 17:29:27
    1、首先了解是什么 是一种数据结构,一种叫做完全二叉树的数据结构。 2、的性质 这里我们用到两种,其实也算是一种。 大顶堆:每个节点的值都大于或者等于它的左右子节点的值。 小顶堆:每个节点的值都...

    1、首先了解堆是什么

    堆是一种数据结构,一种叫做完全二叉树的数据结构。

    2、堆的性质

    这里我们用到两种堆,其实也算是一种。

    大顶堆:每个节点的值都大于或者等于它的左右子节点的值。

    小顶堆:每个节点的值都小于或者等于它的左右子节点的值。

    如上所示,就是两种堆。

    如果我们把这种逻辑结构映射到数组中,就是下边这样

    95823471
    13542897

    这个数组arr逻辑上就是一个堆。

    从这里我们可以得出以下性质(重点)

    对于大顶堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]

    对于小顶堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]

    3、堆排序的基本思想

    了解了以上内容,我们可以开始探究堆排序的基本思想了。

    堆排序的基本思想是:1、将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;2、将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;3、重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了。

    假设给定的无序序列arr是:

    45823971

    1、将无序序列构建成一个大顶堆。

    首先我们将现在的无序序列看成一个堆结构,一个没有规则的二叉树,将序列里的值按照从上往下,从左到右依次填充到二叉树中。

     

    根据大顶堆的性质,每个节点的值都大于或者等于它的左右子节点的值。所以我们需要找到所有包含子节点的节点,也就是非叶子节点,然后调整他们的父子关系,非叶子节点遍历的顺序应该是从下往上,这比从上往下的顺序遍历次数少很多,因为,大顶堆的性质要求父节点的值要大于或者等于子节点的值,如果从上往下遍历,当某个节点即是父节点又是子节点并且它的子节点仍然有子节点的时候,因为子节点还没有遍历到,所以子节点不符合大顶堆性质,当子节点调整后,必然会影响其父节点需要二次调整。但是从下往上的方式不需要考虑父节点,因为当前节点调整完之后,当前节点必然比它的所有子节点都大,所以,只会影响到子节点二次调整。相比之下,从下往上的遍历方式比从上往下的方式少了父节点的二次调整。

    那么,该如何知道最后一个非叶子节点的位置,也就是索引值?

    对于一个完全二叉树,在填满的情况下(非叶子节点都有两个子节点),每一层的元素个数是上一层的二倍,根节点数量是1,所以最后一层的节点数量,一定是之前所有层节点总数+1,所以,我们能找到最后一层的第一个节点的索引,即节点总数/2(根节点索引为0),这也就是第一个叶子节点,所以第一个非叶子节点的索引就是第一个叶子结点的索引-1。那么对于填不满的二叉树呢?这个计算方式仍然适用,当我们从上往下,从左往右填充二叉树的过程中,第一个叶子节点,一定是序列长度/2,所以第一个非叶子节点的索引就是arr.length / 2 -1。

    现在找到了最后一个非叶子节点,即元素值为2的节点,比较它的左右节点的值,是否比他大,如果大就换位置。这里因为1<2,所以,不需要任何操作,继续比较下一个,即元素值为8的节点,它的左节点值为9比它本身大,所以需要交换

    交换后的序列为:

    45923871

    因为元素8没有子节点,所以继续比较下一个非叶子节点,元素值为5的节点,它的两个子节点值都比本身小,不需要调整;然后是元素值为4的节点,也就是根节点,因为9>4,所以需要调整位置

    交换后的序列为:

    95423871

    此时,原来元素值为9的节点值变成4了,而且它本身有两个子节点,所以,这时需要再次调整该节点

    交换后的序列为:

    95823471

    到此,大顶堆就构建完毕了。满足大顶堆的性质。

    2、排序序列,将堆顶的元素值和尾部的元素交换

    交换后的序列为:

    15823479

    然后将剩余的元素重新构建大顶堆,其实就是调整根节点以及其调整后影响的子节点,因为其他节点之前已经满足大顶堆性质。

    交换后的序列为:

    85723419

    然后,继续交换,堆顶节点元素值为8与当前尾部节点元素值为1的进行交换

    交换后的序列为:

    15723489

    重新构建大顶堆

    交换后的序列为:

    75423189

    继续交换

    交换后的序列为:

    15423789

    重新构建大顶堆

    构建后的序列为:

    53421789

    继续交换

    交换后的序列为:

    13425789

    重新构建大顶堆

    构建后的序列为:

    43125789

    继续交换

    交换后的序列为:

    23145789

    重新构建大顶堆

    构建后的序列为:

    32145789

    继续交换

    交换后的序列为:

    12345789

    重新构建大顶堆

    构建后的序列为:

    21345789

    继续交换

    交换后的序列为:

    12345789

    此时,序列排序完成。以上就是整个堆排序的逻辑。

    4、堆排序的代码实现(java版本)

    public class HeapSort {
    
    	public static void heapSort(int[] arr) {
    		if (arr == null || arr.length == 0) {
    			return;
    		}
    		int len = arr.length;
    		// 构建大顶堆,这里其实就是把待排序序列,变成一个大顶堆结构的数组
    		buildMaxHeap(arr, len);
    
    		// 交换堆顶和当前末尾的节点,重置大顶堆
    		for (int i = len - 1; i > 0; i--) {
    			swap(arr, 0, i);
    			len--;
    			heapify(arr, 0, len);
    		}
    	}
    
    	private static void buildMaxHeap(int[] arr, int len) {
    		// 从最后一个非叶节点开始向前遍历,调整节点性质,使之成为大顶堆
    		for (int i = (int)Math.floor(len / 2) - 1; i >= 0; i--) {
    			heapify(arr, i, len);
    		}
    	}
    
    	private static void heapify(int[] arr, int i, int len) {
    		// 先根据堆性质,找出它左右节点的索引
    		int left = 2 * i + 1;
    		int right = 2 * i + 2;
    		// 默认当前节点(父节点)是最大值。
    		int largestIndex = i;
    		if (left < len && arr[left] > arr[largestIndex]) {
    			// 如果有左节点,并且左节点的值更大,更新最大值的索引
    			largestIndex = left;
    		}
    		if (right < len && arr[right] > arr[largestIndex]) {
    			// 如果有右节点,并且右节点的值更大,更新最大值的索引
    			largestIndex = right;
    		}
    
    		if (largestIndex != i) {
    			// 如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点值互换
    			swap(arr, i, largestIndex);
    			// 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。
    			heapify(arr, largestIndex, len);
    		}
    	}
    
    	private static void swap (int[] arr, int i, int j) {
    		int temp = arr[i];
    		arr[i] = arr[j];
    		arr[j] = temp;
    	}
    }

    5、复杂度分析

    因为堆排序无关乎初始序列是否已经排序已经排序的状态,始终有两部分过程,构建初始的大顶堆的过程时间复杂度为O(n),交换及重建大顶堆的过程中,需要交换n-1次,重建大顶堆的过程根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以它最好和最坏的情况时间复杂度都是O(nlogn),空间复杂度O(1)。

    展开全文
  • 堆排序的复杂度

    2020-02-25 11:00:20
     初始化建只需要对二叉树的非叶子节点调用adjusthead()函数,由下至上,由右至左选取非叶子节点来调用adjusthead()函数。那么倒数第二层的最右边的非叶子节点就是最后一个非叶子结点。  假设高度为k,则从倒数第...

    一.初始化建堆
      假设高度为k,则从倒数第二层右边的节点开始,这一层的节点都要执行子节点比较然后交换(如果顺序是对的就不用交换);倒数第三层呢,则会选择其子节点进行比较和交换,如果没交换就可以不用再执行下去了。如果交换了,那么又要选择一支子树进行比较和交换;高层也是这样逐渐递归。
      那么总的时间计算为:s = 2^( i - 1 ) * ( k - i );其中 i 表示第几层,2^( i - 1) 表示该层上有多少个元素,( k - i) 表示子树上要下调比较的次数。
      S = 2^(k-2) * 1 + 2(k-3)*2…+2*(k-2)+2(0)*(k-1) ===> 因为叶子层不用交换,所以i从 k-1 开始到 1;
       等式左右乘上2,然后和原来的等式相减,就变成了:
       S = 2^(k - 1) + 2^(k - 2) + 2^(k - 3) … + 2 - (k-1)
       除最后一项外,就是一个等比数列了,直接用求和公式:S = { a1[1 - (q^n)] } / (1-q);
      S = 2^k -k -1;又因为k为完全二叉树的深度,而log(n) =k,把此式带入;
      得到:S = n - log(n) -1,所以时间复杂度为:O(n)

    二.排序重建堆
      在取出堆顶点放到对应位置并把原堆的最后一个节点填充到堆顶点之后,需要对堆进行重建,只需要对堆的顶点调用adjustheap()函数。
      每次重建意味着有一个节点出堆,所以需要将堆的容量减一。adjustheap()函数的时间复杂度k=log(n),k为堆的层数。所以在每次重建时,随着堆的容量的减小,层数会下降,函数时间复杂度会变化。重建堆一共需要n-1次循环,每次循环的比较次数为log(i),则相加为:log2+log3+…+log(n-1)+log(n)≈log(n!)。可以证明log(n!)和nlog(n)是同阶函数:
      所以时间复杂度为O(nlogn)

    三.总结
      初始化建堆的时间复杂度为O(n),排序重建堆的时间复杂度为nlog(n),所以总的时间复杂度为O(n+nlogn)=O(nlogn)。另外堆排序的比较次数和序列的初始状态有关,但只是在序列初始状态为堆的情况下比较次数显著减少,在序列有序或逆序的情况下比较次数不会发生明显变化。

    展开全文
  • 堆排序及其时间复杂度

    千次阅读 2021-01-17 18:41:04
    堆排序//这里构建数组过程只是做一个简单的示例,复杂情况暂不考虑//接受键盘输入n个数,构建数组int *setUpArr(){int n;scanf("%d",&n);int *arr = (int *)malloc(sizeof(int)*n);if(arr){for(int i = 0; i <...
  • #include #include using namespace std; template<typename E> inline void swap(E A[], int i, int ... cout 一般条件下插入排序比较次数为:" [0] ; cout 一般条件下插入排序交换次数为:" [0] ; int c[5] = { 5,...
  • 一、堆排序 1、排序原理 堆,是一种类似于二叉树的结构。也就是说,在堆中,每一个待排序序列的元素都可以看做是一个堆的节点,而堆的每一个节点,又有两个子节点。 我们称图中任何一个节点下方的左右两个...
  • 堆排序算法”(C语言实现)

    千次阅读 多人点赞 2022-04-03 23:02:30
    堆排序1.堆的概念及性质2.向下调整和向上调整两大算法二级目录三级目录 一.堆排序 1.堆的概念及性质 1.1堆的概念 a. 堆是一种基本的数据结构。在这里我用数组来形容,在一个二叉堆的数组中,每一个元素(根)都要...
  • 这篇堆和堆排序是二叉树的应用分析,回答了这个问题。 堆(Heap) 堆是什么 堆是一颗有最大堆和最小堆之分 / 在最大堆中每个节点的值都大于等于其子节点(如果有子节点的话)的值 / 最小堆定义类似 / 的完全二叉树。 ...
  • 十大经典排序算法-堆排序,计数排序,桶排序,基数排序 1-堆排序 算法思想: 算法图解: 示例代码: 在这里插入代码片 复杂度分析: 2-计数排序 算法思想: 算法图解: 示例代码: 在这里插入代码片 复杂度分析: 3-桶排序 ...
  • 写了几个排序的方法,随机生成三个整形数组,然后分别用多种方法进行排序计算比较次数与交换次数
  • 各种排序算法的比较次数

    万次阅读 多人点赞 2015-08-08 21:16:27
    借助比较排序每次比较贡献O(1)的复杂度 插入排序  最少n-1 最多n(n-1)/2 冒泡排序  最少n-1 最多n(n-1)/2 选择排序  n(n-1)/2 快速排序  int partition(int *arr , int low , ...
  • 堆排序是由1991年的计算机先驱奖获得者、斯坦福大学计算机科学系教授罗伯特.弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)在1964年共同发明了的一种排序算法( Heap Sort ); 堆排序(Heapsort)是指利用堆积...
  • 堆排序中每次堆调整后的次序

    千次阅读 2020-04-24 20:07:32
    堆排序是对简单选择排序的一种改进,改进的着眼点是如何减少选择的比较次数。在特定的条件下,堆排序的效率是明显优于快速排序的。那么,堆排序是如何减少记录的比较次数,提高整个排序的效率的? 需求分析 问题描述...
  • 堆排序包括两个阶段,初始化建堆和重建堆。所以堆排序的时间复杂度由这两方面组成,下面分别进行分析。先post一个实现代码,便于分析。 #include <stdio.h> void swap(int *a, int *b); void adjustHeap...
  • 堆排序和选择排序的比较

    千次阅读 2015-09-12 15:09:23
    首先要说明的是,选择排序和堆排序都属于原址排序( 在排序算法中,如果输入数组中仅有常数个元素需要在排序过程中存储在数组之外,则称排序算法是原址的。 插入排序、堆排序、快速排序等都是原址排序。 ...
  • 简单的三种排序 总结:排序算法中最基本的三种算法(简单选择,冒泡,插入),这三种排序...1、归并排序:堆排序结构复杂,直接利用完全二叉树。1.分解:将当前区间一分为二,即求分裂点2.求解:递归地对两个子...
  • 内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列。 排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列。排序...
  • 5 直接选择的优化版之堆排序 自学成才的计算机科学家 Flody 堆排序的基本概念 堆排序的算法思想 堆排序是如何工作的 应用堆排序得到升序排序的例子 算法评价 6 总结 1 你会学到什么?彻底弄明白常用的排序算法的...
  • 堆排序 练习题

    千次阅读 2020-08-27 15:39:03
    6.1 1、在高度为h的中,元素个数最多、最少分别为? 解:由序性质,是一个底层完全充满的树,因此除第h层外,每层的结点个数为2^(k-1),k为当前层数。 那么元素总个数为:N = 1 + 2 + 2^2 + 2^3 + ...
  • 堆排序时间复杂度

    千次阅读 2019-03-06 17:08:57
    注:本文转载于两篇博文,感谢博主 转载于: https://blog.csdn.net/yuzhihui_no1/article/details/44258297... ... 堆排序是由1991年的计算机先驱奖获得者、斯坦福大学计算机科学系教授罗伯特.弗洛伊德(Robert W.Fl...
  • 文章目录直接插入排序代码实现复杂度的计算希尔排序希尔排序的预排序代码实现选择排序代码实现堆排序冒泡排序代码实现 ???? 注:以下排序都是以排升序为例。 直接插入排序 直接插入排序的主要思路就是: 1.首先...
  • 排序算法想必大家不陌生,今天就来详细的做个总结,包括排序算法的复杂度,稳定性,实现方式。
  • 先是基础:最大堆(大顶堆)和最小堆(小顶堆)详解;然后剖析“堆排序”的实质和思路过程,然后又代码逐步实现!
  • **线性时间非比较排序:**不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较排序。 0.2 算法复杂度 0.3 相关概念 稳定:如果a原本在b前面,而a=b...
  • 最近算法老师让大家抓紧时间完成算法作业,总共四个题目。这几个题目都很不错,我计划着把这四个... 任务要求:实现排序类,公共函数包括冒泡排序、快速排序(递归)、堆排序。将递归算法改写为非递归的,进行比较
  • 堆排序——C#实现

    千次阅读 2017-10-16 17:10:16
     堆排序(Heap Sort)是利用一种被称作二叉堆的数据结构进行排序的排序算法。  二叉堆在内部维护一个数组,可被看成一棵近似的完全二叉树,树上每个节点对应数组中的一个元素。除最底层外,该树是满的。  二叉堆...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 63,557
精华内容 25,422
关键字:

堆排序比较次数计算

友情链接: 2267PDU-0608lunxun - 02.rar