选择排序----直接选择排序与堆排序

选择排序即每次从待排序的数列中选择一个最小的元素,然后把它放在已排好序列的最前面(假定这里从小到大排序),直至序列完全有序。
选择排序分为线性结构的直接选择排序与非线性的堆排序,后者是用相当于把树的元素存在数组中,通过元素下标来区分孩子结点与父亲结点等等

1.直接选择排序
     直接上代码
void select_sort(int* a, int n) 
{
	for (int i = 0; i < n; ++i)
    {
        int k = i; //记录待排序元素下标

        for (int j = i + 1; j < n; ++j)
            if (a[k] > a[j]) //不断寻找最小元素,并用k保留最下元素下标
                k = j;
                
		 

        if (i != k) //如果找到的最小元素的下标与待排序元素下标不等于,证明不是同一个元素侧交换
        {
            int t = a[i];
            a[i] = a[k];
            a[k] = t;
        }
	/* 不要用下面的循环代替上面的for循环与一个if语句,虽然功能一样,但是前者效率更高 
	for (int j = i + 1; j < n; ++j)
		{
			if (a[k] > a[j])
			{
				int t = a[k];
				a[k] = a[j];
				a[j] = t;
			} 
		}
	*/ 
    }
} 

2.堆排序
    首先是建立相应堆,如果是从小到大排序即建立最大堆,如果从大到小侧建立最小堆,然后在进行排序
    假设这里是从小到大排序建立最大堆。
    最大堆的建立:从堆的第一个分支结点开始,依次与其孩子结点比较,找到最大的那个结点让其位于父亲结点的位置,并逐步处理该节点的孩子结点,直至满足父亲结点比  孩子结点值都大。建立之后很明显根节点是序列中最大值的那个。
    这里其实可以看出,堆的特性很利于我们求数列中第K大的数字,这里只需要建立一个大小为K最小堆,堆顶就是第K大的那个元素,比如有10个元素,求第三大的元素,先取三个数字建立一个最小堆,这里假设取前三个数字,将这三个数字建立为最小堆,然后从第四个数字开始与该堆顶元素比较,如果比堆顶元素小侧舍弃不要,如果被堆顶元素大侧替换堆顶元素并维护该最小堆,用同样方法依次处理第5-10个元素。
   排序过程:由于最大堆的堆顶元素即为该序列的最大元素,所以让他与堆顶最后一个元素交换,然后维护堆(此时把堆的大小减一,因为已经归位一个元素),依次处理直至堆的大小为1

   建立堆
//把当前需要下移的元素下移
void siftdown(int* h, int i)
{
	int flag = 0, t;

	while (2 * i <= n && flag == 0) //如果该节点至少有左孩子或者还可以下移已建立最大堆
	{
		if (h[i] > h[2 * i]) //找出左孩子与该节点最大的那个
			t = i;
		else
			t = 2 * i;

		if (2 * i + 1 <= n) //如果有右孩子,找到更大的那个元素下标
			if (h[2 * i + 1] > h[t]) 
				t = 2 * i + 1;

	    if (t != i) //如果最大元素就是当前需要下移元素,侧完全没有必要继续下移
		{
			swap(t, i);
			i = t; //方便继续向下调整,已形成最大堆
		}
		else
			flag = 1; //标志没必要下移了,因为当前元素比它的孩子都大
	}
}

void swap(int* h, int m, int n)
{
	int t;

	t = h[m];
	h[m] = h[n];
	h[n] = t;
}

//建立最大堆
void creat(int* h, int n)
{
	int i;

	for (i = n / 2; i >= 1; i--) //从最大堆的第一个分支结点开始不断下移已建立最大堆
		siftdown(h, i);
}
    堆排序
//堆排序(这里是从小到大排序)
void heapsort(int* h, int n)
{
	while (n > 1)//直到n = 1 即只剩下最后一个数字没有操作,此时也没有必要操作了
	{
		swap(h, 1, n);//最大堆的第一个数字最大,把该最大数移到数组的而最后一个数字去
    	n--; //每次归位一个元素,不断缩小最大堆的大小
    	siftdown(h, 1);//把第一个数字重新更新为最大数
	}
}

直接选择排序:
      时间复杂度: 最好:O(n^2)       平均:O(n^2)        最坏:O(n^2)
堆排序:
     时间复杂度:最好:O(nlog2n)    平均:O(nlog2n)   最坏: O(nlog2n)
两者空间复杂度均为O(1) 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值