5. 線性查找

有些查找問題要用時間複雜度為O(n)的算法來解決。例如寫一個indexof函數,從任意輸入字元串中找出某個字母的位置並返回這個位置,如果找不到就返回-1:

例 11.3. 線性查找

#include <stdio.h>

char a[]="hello world";

int indexof(char letter)
{
	int i = 0;
	while (a[i] != '\0') {
		if (a[i] == letter)
			return i;
		i++;
	}
	return -1;
}

int main(void)
{
	printf("%d %d\n", indexof('o'), indexof('z'));
	return 0;
}

這個實現是最直觀和最容易想到的,但它是不是最快的算法呢?我們知道插入排序也比歸併排序更容易想到,但通常不如歸併排序快。那麼現在這個問題--給定一個隨機排列的序列,找出其中某個元素的位置--有沒有比O(n)更快的算法?比如O(lgn)?請讀者思考一下。

習題

1、實現一個算法,在一組隨機排列的數中找出最小的一個。你能想到的最直觀的算法一定是Θ(n)的,想想有沒有比Θ(n)更快的算法?

2、在一組隨機排列的數中找出第二小的,這個問題比上一個稍複雜,你能不能想出Θ(n)的算法?

3、進一步泛化,在一組隨機排列的數中找出第k小的,這個元素稱為k-th Order Statistic。能想到的最直觀的算法肯定是先把這些數排序然後取第k個,時間複雜度和排序算法相同,可以是Θ(nlgn)。這個問題雖然比前兩個問題複雜,但它也有平均情況下時間複雜度是Θ(n)的算法,將上一節習題1的快速排序算法稍加修改就可以解決這個問題:

/* 從start到end之間找出第k小的元素 */
int order_statistic(int start, int end, int k)
{
	用partition函數把序列分成兩半,中間的pivot元素是序列中的第i個;
	if (k == i)
		返回找到的元素;
	else if (k > i)
		從後半部分找出第k-i小的元素並返回;
	else
		從前半部分找出第k小的元素並返回;
}

請編程實現這個算法。