一、排序
本章以介紹插入排序爲伊始,進而介紹了快速排序,以及隨機選取劃分元素的改進的快速排序,且可根據所要排序元素的多少動態的選擇是進行插入排序還是快速排序的算法(在元素較少的排序中,插入排序的運行效果可能更好)。插入排序與快速排序這裏就不多介紹了。下面看一個這一章的習題。
習題第9題中要求編寫一個程序,在O(n)時間內從數組x[0...n-1]中找到第k個最小的元素,算法可以對x當中的元素進行排序。此算法賴子C.A.R. Hoare,是對快速排序算法的一種修改:
#include <stdio.h>
#include <stdlib.h>
void swap(int x[],int a, int b)
{
int temp = x[a];
x[a] = x[b];
x[b] = temp;
}
int randint(int l,int u)
{
return l+rand()%(u-l+1);
}
void select(int x[],int l,int u,int k)
{
int i,j,temp,t;
if (l>=u)
return;
swap(x,l,randint(l,u));
t = x[l];
i = l;
j = u+1;
while (1)
{
do
{
i++;
} while(i<=u && x[i]<t);
do
{
j--;
} while(x[j]>t);
if (i>j)
break;
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
swap(x,l,j);
if (j<k)
{
select(x,j+1,u,k);
}
else if (j>k)
{
select(x,l,j-1,k);
}
}
void main()
{
int x[8] = {1, -2, 3, 10, -4, 7, 2, -5};
int k;
printf("輸入要找的第k小元素(0<=k<=7):");
scanf("%d",&k);
select(x,0, 7, k);
printf("%d/n", x[k]);
}
問題擴展:分治法找第k小元素。找到數組第K小元素後,有且只有x[0]至x[k-1]是比x[k]小的。所以同樣算法可解決下面問題,複雜度同爲O(n)。
給定一個具有n個元素的整數集,一個整數t以及一個整數k,如何快速確定該整數集是否存在一具有k個元素的子集,其中各元素的總和至多隻能爲t?
#include <stdio.h>
#define MAXN 8
int x[MAXN] = {1, -2, 3, 10, -4, 7, 2, -5};
void swap(int a, int b)
{
int ntemp = x[a];
x[a] = x[b];
x[b] = ntemp;
}
int MinK(int l, int h, int k)
{
if (l > h)
return 0;
int m = l;
for (int i=l+1; i<=h; i++)
{
if (x[i] < x[m])
swap(++m, i);
}
swap(m, l);
if (k == m)
return x[m];
else if (k < m)
return MinK(l, m-1, k);
else
return MinK(m+1, h, k);
}
int main(int argc, char* argv[])
{
//第0小元素是最小元素
int n = MinK(0, MAXN-1, 6);
printf("%d/n", n);
return 0;
}
注:另外,要求一個數組的第k小或者第k大的數則可通過建立最大最小堆來實現,時間複雜度爲O(nlogk)。