C语言----堆排序、快速排序(寻找第K大)

        在学习堆排序之前,首先需要了解堆的含义:在含有 n 个元素的序列中,如果序列中的元素满足下面其中一种关系时,此序列可以称之为堆。

  • ki ≤ k2i 且 ki ≤ k2i+1(在 n 个记录的范围内,第 i 个关键字的值小于第 2*i 个关键字,同时也小于第 2*i+1 个关键字),这是小顶堆
  • ki ≥ k2i 且 ki ≥ k2i+1(在 n 个记录的范围内,第 i 个关键字的值大于第 2*i 个关键字,同时也大于第 2*i+1 个关键字),这是大顶堆

         对于堆的定义也可以使用完全二叉树来解释,因为在完全二叉树中第 i 个结点的左孩子恰好是第 2i 个结点,右孩子恰好是 2i+1 个结点。如果该序列可以被称为堆,则使用该序列构建的完全二叉树中,每个根结点的值都必须不小于(或者不大于)左右孩子结点的值。

        堆排序过程的代码实现需要解决两个问题:

  1. 如何将得到的无序序列转化为一个堆?
  2. 在输出堆顶元素之后(完全二叉树的树根结点),如何调整剩余元素构建一个新的堆?

         给定一个数组,怎么将数组用堆排序。目前网上大部分资料都是从数组下标1开始,这样就需要另外申请一个数组,索引为0的元素叫哨兵。

下面直接给出代码

#include <stdio.h>
#include <stdlib.h>

void adjustHeap(int *a,int s,int n)
{
	int rc = a[s];
	int j=0;
	for(j=2*s;j<=n;j=2*j)
	{
		if(j+1<=n && a[j] < a[j+1])
			j++;
		if(rc > a[j])
			break;

		a[s] = a[j];
		s = j;
	}
	a[s] = rc;
}

void HeapSort(int *a,int m)
{
	int i=0,temp=0;
	for(i=m/2;i>0;i--)
	{
		adjustHeap(a,i,m);
	}
	for(i=m;i>0;i--)
	{
		temp = a[1];
		a[1] = a[i];
		a[i] = temp;
		adjustHeap(a,1,i-1);
	}
}

int main()
{
	int a[11] = {-1,1,3,5,7,9,0,2,6,4,8};
	HeapSort(a,10);
	for(int i=1;i<11;i++)
		printf("%d ",a[i]);
	return 0;
}

结果

[root@localhost heapsort]# gcc -o heapsort heapsort.c -std=gnu99
[root@localhost heapsort]# 
[root@localhost heapsort]# ./heapsort
0 1 2 3 4 5 6 7 8 9

下面给出我自己琢磨的从数组下标0进行排序的堆排序算法

#include <stdio.h>
#include <stdlib.h>

void adjustHeap(int *a,int s,int n)
{
	int rc = a[s];
	int j=0;
	for(j=2*s+1;j<n;j=2*j+1)
	{
		if(j+1<n && a[j] < a[j+1])
			j++;
		if(rc > a[j])
			break;

		a[s] = a[j];
		s = j;
	}
	a[s] = rc;
}

void HeapSort(int *a,int m)
{
	int i=0,temp=0;
	for(i=m/2-1;i>=0;i--)//从数组下标0开始算,则具有叶子节点的计算需要重新调整为m/2-1
	{
		adjustHeap(a,i,m);
	}
	for(i=m-1;i>0;i--)
	{
		temp = a[0];
		a[0] = a[i];
		a[i] = temp;
		adjustHeap(a,0,i);//此处i不再是上面的i-1,因为i直接从m-1开始,adjustHeap函数中j<n,不能再等于n

	}
}
int main()
{
	int a[10] = {1,3,5,7,9,0,2,6,4,8};
	HeapSort(a,10);
	for(int i=0;i<10;i++)
		printf("%d ",a[i]);
	return 0;
}

现在用堆排序来做leecode上的题

         题目提示用快速排序的思想,后面会给出用快排的做法,这里用堆排序快速找出第K大的数,使用大顶堆,每次调整后,交换出来的a[0]就是当前最大的数,这样进行K次调整后,出来的数就是第K大的数。

/**
 * 
 * @param a int整型一维数组 
 * @param aLen int a数组长度
 * @param n int整型 
 * @param K int整型 
 * @return int整型
 */
void adjustHeap(int *a,int s,int n)
{
	int rc = a[s];
	int j=0;
	for(j=2*s+1;j<n;j=2*j+1)
	{
		if(j+1<n && a[j] < a[j+1])
			j++;
		if(rc > a[j])
			break;

		a[s] = a[j];
		s = j;
	}
	a[s] = rc;
}
int findKth(int* a, int aLen, int n, int K ) 
{
    // write code here
    int i = 0;
    for(i=aLen/2-1;i>=0;i--)
    {
        adjustHeap(a,i,aLen);
    }
    for(i=aLen-1;i>0;i--)
    {
        if(aLen - i == K)
            break;
        a[0] = a[i];
        adjustHeap(a,0,i);
    }
    return a[0];
}

 下面用快速排序的思想来解这道题

 

int getIndex(int *a,int low,int high)
{
    int rc = a[low];
    while(low<high)
    {
        while(low<high && a[high] >= rc)
            high--;
        a[low] = a[high];
        
        while(low<high && a[low] <= rc)
            low++;
        a[high] = a[low];
    }
    a[low] = rc;
    return low;
}
void quickSort(int *a,int low, int high)
{
    if(low<high)
    {
        int index = getIndex(a,low,high);
        quickSort(a,low,index-1);
        quickSort(a,index+1,high);
    }
}
int findKth(int* a, int aLen, int n, int K ) 
{
    //int KthNum = aLen - K;
    //int retKnum;
    quickSort(a,0,aLen-1);
    return a[aLen - K];
}

 此题我原本的思路就是当getIndex的返回值index,在aLen-K的位置上即可终止递归,这个值我想用一个全局变量带出来,但是编译不过,只有排完再取值了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ftzchina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值