此算法借用快速排序算法。

这个快速选择算法主要利用递归调用,数组存储方式。包含3个文件,头文件QuickSelect.h,库函数QuickSelect.c,测试文件TestQuickSelect。

其中Cutoff可以自己给定,这个当开始给定的数组(或者递归调用产生的子数组)的元素个数<=20个时,采用插入排序。一般认为当元素个数<=20时,插入排序更快。这个20不是固定的,在这附近浮动都可以的。

头文件QuickSelect.h

 1 #ifndef QuickSelect_H
 2 #define QuickSelect_H
 3 #define Cutoff 20
 4 typedef int ElementType;
 5 ElementType Median3(ElementType A[], int left, int right);
 6 void Swap(ElementType *p, ElementType*q);
 7 void InsertionSort(ElementType A[], int N);
 8 ElementType QuickSelect(ElementType A[],int k, int N);
 9 ElementType Qselect(ElementType A[],int k, int Left, int Right);
10 void PrintMatrix(ElementType A[], int N);
11 #endif // !QuickSelect_H

 

库函数QuickSelect.c

 1 #include "QuickSelect.h"
 2 #include<stdio.h>
 3 //通过三数中值分割法获得数组的枢纽元
 4 ElementType Median3(ElementType A[], int Left, int Right)
 5 {
 6     int Center = (Left + Right) / 2;
 7     if (A[Left] > A[Right])
 8         Swap(&A[Left], &A[Right]);
 9     if (A[Left] > A[Center])
10         Swap(&A[Left], &A[Center]);
11     if (A[Center] > A[Right])
12         Swap(&A[Center], &A[Right]);
13     //上述三次交换使得:A[Left]<A[Center]<A[Right]
14     Swap(&A[Center], &A[Right - 1]);
15     return A[Right - 1];//返回枢纽元;
16 }
17 
18 //交换指针p和q各自指向的值;
19 void Swap(ElementType * p, ElementType * q)
20 {
21     ElementType Tmp;
22     Tmp = *p;
23     *p = *q;
24     *q = Tmp;
25 }
26 
27 //当开始给定的数组(或者递归调用产生的子数组)的元素个数<=20个时,采用插入排序。
28 void InsertionSort(ElementType A[], int N)
29 {
30     int j, P;
31     ElementType Tmp;
32     for (P = 1; P < N; P++)
33     {
34         Tmp = A[P];
35         for (j = P; j > 0 && A[j - 1] > Tmp; j--)
36             A[j] = A[j - 1];
37         A[j] = Tmp;
38     }
39 }
40 
41 //快速选择算法驱动程序
42 ElementType QuickSelect(ElementType A[],int k, int N)
43 {
44     return Qselect(A, k-1, 0, N - 1);//该程序即为,输入,k,返回A[k]。因为A从0开始存储,如果想找第5个最小值,其实找的是A[4],所以当我们找第k个值时,应输入k-1。
45 }
46 
47 //快速选择核心算法
48 ElementType Qselect(ElementType A[], int k, int Left, int Right)
49 {
50     int i, j;
51     ElementType Pivot;
52     if (Left + Cutoff - 1 <= Right)//此处Cutoff-1是为了和N-1=Right对应上
53     {
54         Pivot = Median3(A, Left, Right);//调用枢纽元函数选取枢纽元
55         i = Left; j = Right - 1;
56         for (; ;)
57         {
58             while (A[++i] < Pivot);
59             while (A[--j] > Pivot);
60             if (i < j) Swap(&A[i], &A[j]);
61             else break;
62         }
63         Swap(&A[i], &A[Right - 1]);
64         if (k < i)
65             Qselect(A, k, Left, i - 1);//对剩下小于枢纽元的元素递归排序
66         else if (k>i)
67             Qselect(A, k, i + 1, Right);//对剩下大于枢纽元的元素递归排序
68         //当k=i时,即查询的值==枢纽元,则找到了,返回A[k]
69     }
70     else//当最后子数组只有Cutoff个,则采用插入排序。
71         InsertionSort(A + Left, Right - Left + 1);
72     return A[k];
73 }
74 
75 //打印数组
76 void PrintMatrix(ElementType A[], int N)
77 {
78     for (int i = 0; i < N; i++)
79         printf("%d ", A[i]);
80 }

 

测试文件TestQuickSelect

 1 #include "QuickSelect.h"
 2 #include <stdio.h>
 3 #include<time.h>
 4 #include<stdlib.h>
 5 #define N 100000
 6 int main()
 7 {
 8     ElementType A[N] ;
 9     int ID;
10     srand((unsigned)time(NULL));
11     for (int i = 0; i < N; i++)
12     {
13         //A[i] = rand() % N;
14         A[i] =N-i;//100000个数,倒序排
15     }
16         
17     printf("\n");
18     //PrintMatrix(A, N);
19     printf("请输入要查询的ID:");
20     scanf_s("%d", &ID);
21     printf("Result:%d",QuickSelect(A, ID, N));
22     printf("\n");
23 }

posted on 2016-12-29 13:42  新爱代  阅读(1286)  评论(0编辑  收藏  举报