[jobdu]最小的K个数

一开始马上想起来寻找第k小的数,是采用快排的partition方法。但因为题目要把k之前的数排序输出,这个方法就不是很合适,因为(随机化后:http://blog.csdn.net/liangbopirates/article/details/9377105)它最差能在O(n)找到第k小的数,那么就要最差k*O(n)。如果对前面部分排序那就是O(k*logk) + O(n)了。都不合适,看来最合适的还是使用堆,能做到O(n*logK)。

但partition方法和堆方法比较,有个好处就是inplace,不占多余内存,在海量数据处理的时候有这个好处。

下面这段代码是寻找第k小的数,其精华部分是partition方法,注意这个方法的写法,维基百科和算法导论上都是这样的,比一般的写法简洁,需要记下来。本质是分了三段,第一段小于等于pivot,第二段大于pivot,第三段是未处理的。idx一直指向第二段的第一个,或者说第一段最右边过去一个,i一直指向第二段的最右边,或是第三段的最左边。那么当a[i]<pivot的时候,就把a[i]和a[idx]交换,然后idx++,这样就继续保持了这个性质。

#include <iostream>

using namespace std;



void swap(int& a, int& b)

{

	int tmp = a;

	a = b;

	b = tmp;

}



// start、end分别为数组第一个元素和最后一个元素的索引

int partition(int arr[], int start, int end)

{

    int pivot = arr[end];

    int idx = start;

    //这个循环比一般的写法简洁高效,维基百科上和算法导论上的

    for(int i = start; i < end; i++) {

        if(arr[i] < pivot) {

            swap(arr[i], arr[idx]);

            ++idx;

        }

    }

    swap(arr[idx], arr[end]);

    return idx;

}



int main()

{

	int n; // count

	cin >> n;

	int m; // index

	cin >> m;

	int* a = new int[n];

	for (int i = 0; i < n; i++)

	{

		cin >> a[i];

	}

	int start = 0;

	int end = n - 1;

	while (true)

	{

		int c = partition(a, start, end);

		if (c == (m-1))

		{

			break;

		}

		if (c > (m - 1))

		{

			end = c - 1;

		}

		else

		{

			start = c + 1;

		}

	}

	cout << a[m-1] << endl;

	delete[] a;

	system("pause");

}

下面是采取堆的方式,(待续):

你可能感兴趣的:(job)