排序算法——选择排序

目录

 

选择排序

1.1直接选择

1.1.1思路

1.1.2例子

1.1.3 复杂度和稳定性分析

1.1.4 java代码

1.2堆排序

1.2.1思路

1.2.2例子

1.2.3 复杂度和稳定性分析

1.2.4 java代码


选择排序

1.1直接选择

1.1.1思路

将指定排序位置与其他数组元素分别对比,如果满足条件就交换元素值,注意这里区别冒泡排序,不是交换相邻元素,而是把满足条件的元素与指定的排序位置交换(如从最后一个元素开始排序),这样排序好的位置逐渐扩大,最后整个数组都成为已排序好的格式。

1.1.2例子

由小到大进行选择排序,每次选择并交换后各排序码位置的变动情况,中括号中为待排序区间,中括号前面为已经排好的元素。

 

1.1.3 复杂度和稳定性分析

空间上看:

它只需要一个辅助空间temp ,因此其空间复杂度位O(1)

时间上看:

待排序序列为正序,移动次数最小,为 0 次;待排序序列为逆序时,移动次数最多,为 3(n-1) 次。无论记录的初始排列如何,关键码的比较次数相同,第 i 趟排序需进行 n-i 次关键码的比较,而简单选择排序需要进行 n-1 趟排序,因此,总的比较次数为 ,为 O()。

稳定性

假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。

因此是不稳定的。

1.1.4 java代码

public void selectSort(int[] x) {
		if(x.length!=0) {
			int temp = 0;
			for(int i = 0;i<x.length;i++) {
				int min = i;
				for(int j = i;j<x.length;j++) {
					if(x[j] <= x[min]) {
						min = j;
					}
				}
				temp = x[min];
				x[min] = x[i];
				x[i] = temp;
			}
		}
}

1.2堆排序

1.2.1思路

堆排序,就是以堆的形式去排序。堆是一种特殊的完全二叉树结构。

完全二叉树,其特点在于:

  1. 从作为第一层的根开始,除了最后一层之外,第N层的元素个数都必须是2的N次方;第一层2个元素,第二层4个,第三层8个,以此类推。
  2. 而最后一行的元素,都要紧贴在左边,换句话说,每一行的元素都从最左边开始安放,两个元素之间不能有空闲,具备了这两个特点的树,就是一棵完全二叉树。

当根节点的左右子树都是堆时(根节点不满足堆的性质),可以通过一次向下的调整来将其变换成一个堆。

1.将长度为n的待排序的数组进行堆有序化构造成一个大顶堆
 
2.将根节点与尾节点交换并输出此时的尾节点
 
3.将剩余的n -1个节点重新进行堆有序化
 
4.重复步骤2,步骤3直至构造成一个有序序列

完全二叉树: 除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐
满二叉树:除了叶子结点之外的每一个结点都有两个孩子,每一层(当然包含最后一层)都被完全填充
完满二叉树除了叶子结点之外的每一个结点都有两个孩子结点

 

大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大

小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小

1.2.2例子

{5, 2, 6, 0, 3, 9, 1, 7, 4, 8}

在构造有序堆时,我们开始只需要扫描一半的元素(n/2-1 ~ 0)即可,为什么?

因为(n/2-1)~0的节点才有子节点,如图1,n=8,(n/2-1) = 3  即3 2 1 0这个四个节点才有子节点

第一次找到[n/2]处,进行构造:

我们比较父节点,左右孩子结点的大小,将最大的作为堆顶

第二次,我们对上次找到位置-1即可,找到结点0,对其左右孩子比较,构造这三个结点的最大堆

第三次,我们找到结点6,要对其进行构造,结果如下

第四次(重点),我们不止要构造双亲和左右孩子,我们还要比较其孩子结点为根的堆是否正确,不然我们需要进行调整

我们发现将8,7,2三个结点变为了最大堆,但是其中2,3子树不再是一个最大堆,我们需要对其修改

第五次:选取结点9进行构造

发现以结点5为根的子树不是最大堆,我们需要进行调整

完成最大堆的构建

 

1.2.3 复杂度和稳定性分析

空间上看:

它只需要一个辅助空间temp ,因此其空间复杂度位O(1)

时间上看:

运行时间主要消耗在构造堆和重建堆时的反复筛选上。
构造堆的时间复杂度为O(n)
重建堆时时间复杂度为O(nlogn)。
所以总体就是O(nlogn)。
不适合排序序列个数较少的情况

稳定性

假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。

因此是不稳定的。

1.2.4 java代码

     //堆排序
     public static void heapSort(int[] a) {
         buildMaxHeap(a);
         for(int i=a.length-1;i>=0;i--) {
             int temp=a[0];
             a[0]=a[i];
             a[i]=temp;
             adjustDown(a,0,i);  //将剩余len-1调整为大顶堆,循环,所以用i表示
         }
     }
     //建立大顶堆
     public static void buildMaxHeap(int[] a) {
         for(int i=(a.length/2)-1;i>=0;i--) {
             adjustDown(a,i,a.length);
         }
     }
     //向下调整
     public static void adjustDown(int[] a,int i,int len) {
         int temp,j;
         temp=a[i];
         for(j=2*i+1;j<len;j=2*j+1) {       //j为当前i的子节点,默认为左节点
             if(j+1<len&&a[j+1]>a[j])       //如果右节点大,则选右节点
                 j++;
             if(a[j]<=temp)                 //若子节点都比初始值temp小,说明找到了位置
                 break;
             else {                           
                 a[i]=a[j];                   //如果没有终止,那么将子节点中数值大的上调至i处    
                 i=j;                       //同时i下降到j这个位置
             }
         }
         a[i]=temp;                           //将temp放在最终的位置
     }
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值