码迷,mamicode.com
首页 > 其他好文 > 详细

Binary Search and Quicksort

时间:2015-07-23 23:10:31      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:

 

1. stdlib/bsearch.c

  以下代码实现了有序数组的二分搜索。

 1 /*    $NetBSD: bsearch.c,v 1.14.6.1 2012/04/17 00:05:25 yamt Exp $    */
 2 
 3 /*
 4  * Copyright (c) 1990, 1993
 5  *    The Regents of the University of California.  All rights reserved.
 6  *
 7  * Redistribution and use in source and binary forms, with or without
 8  * modification, are permitted provided that the following conditions
 9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS‘‘ AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 #if 0
35 static char sccsid[] = "@(#)bsearch.c    8.1 (Berkeley) 6/4/93";
36 #else
37 __RCSID("$NetBSD: bsearch.c,v 1.14.6.1 2012/04/17 00:05:25 yamt Exp $");
38 #endif
39 #endif /* LIBC_SCCS and not lint */
40 
41 #include <assert.h>
42 #include <errno.h>
43 #include <stdlib.h>
44 
45 /*
46  * Perform a binary search.
47  *
48  * The code below is a bit sneaky.  After a comparison fails, we
49  * divide the work in half by moving either left or right. If lim
50  * is odd, moving left simply involves halving lim: e.g., when lim
51  * is 5 we look at item 2, so we change lim to 2 so that we will
52  * look at items 0 & 1.  If lim is even, the same applies.  If lim
53  * is odd, moving right again involes halving lim, this time moving
54  * the base up one item past p: e.g., when lim is 5 we change base
55  * to item 3 and make lim 2 so that we will look at items 3 and 4.
56  * If lim is even, however, we have to shrink it by one before
57  * halving: e.g., when lim is 4, we still looked at item 2, so we
58  * have to make lim 3, then halve, obtaining 1, so that we will only
59  * look at item 3.
60  */
61 void *
62 bsearch(const void *key, const void *base0, size_t nmemb, size_t size,
63     int (*compar)(const void *, const void *))
64 {
65     const char *base = base0;
66     size_t lim;
67     int cmp;
68     const void *p;
69 
70     _DIAGASSERT(key != NULL);
71     _DIAGASSERT(base0 != NULL || nmemb == 0);
72     _DIAGASSERT(compar != NULL);
73 
74     for (lim = nmemb; lim != 0; lim >>= 1) {
75         p = base + (lim >> 1) * size;
76         cmp = (*compar)(key, p);
77         if (cmp == 0)
78             return __UNCONST(p);
79         if (cmp > 0) {    /* key > p: move right */
80             base = (const char *)p + size;
81             lim--;
82         }        /* else move left */
83     }
84     return (NULL);
85 }

  以上代码的正确性由其循环变式和不变式共同保证。设欲搜索的结果为 $R$(如果存在的话),每次迭代保证 $R\in[base,base+lim)$,迭代后 $lim$ 至少减半。

  在第一轮迭代开始之前,以上命题显然成立。假设某次迭代前有 $R\in[base,base+lim)$,我们首先计算 $p=base+\lfloor lim/2\rfloor$ 的值并与 *key 进行比较:

  (i) 如果二者相等则 $p$ 所在指针即为搜索结果,直接返回;

  (ii) 如果 (*compar)(key,p)<0,则说明 $R\in[base,p)=[base,base+\lfloor lim/2 \rfloor)$,故直接赋值 $lim := \lfloor lim/2\rfloor$;

  (iii) 如果 (*compar)(key,p)>0,则说明 $R\in[p+1,base+lim)=[base+\lfloor lim/2\rfloor+1,base+lim)$,需要赋值 $base := p+1$ 和 $$\begin{align*}lim&:= lim-\lfloor lim/2\rfloor-1 = \lceil lim/2\rceil-1\\ &= \lfloor(lim+1)/2\rfloor-1 = \lfloor(lim-1)/2\rfloor\end{align*}$$

  第一种情况退出循环不必考虑,其余两种都有 $lim_{new}\leq \lfloor lim_{old}/2\rfloor$,保证循环能够终止。

 

2. stdlib/qsort.c

  以下代码实现了快速排序,我已根据自己理解做了部分注释。

  1 /*    $NetBSD: qsort.c,v 1.21.4.1 2012/10/30 18:58:59 yamt Exp $    */
  2 
  3 /*-
  4  * Copyright (c) 1992, 1993
  5  *    The Regents of the University of California.  All rights reserved.
  6  *
  7  * Redistribution and use in source and binary forms, with or without
  8  * modification, are permitted provided that the following conditions
  9  * are met:
 10  * 1. Redistributions of source code must retain the above copyright
 11  *    notice, this list of conditions and the following disclaimer.
 12  * 2. Redistributions in binary form must reproduce the above copyright
 13  *    notice, this list of conditions and the following disclaimer in the
 14  *    documentation and/or other materials provided with the distribution.
 15  * 3. Neither the name of the University nor the names of its contributors
 16  *    may be used to endorse or promote products derived from this software
 17  *    without specific prior written permission.
 18  *
 19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS‘‘ AND
 20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 29  * SUCH DAMAGE.
 30  */
 31 
 32 #include <sys/cdefs.h>
 33 #if defined(LIBC_SCCS) && !defined(lint)
 34 #if 0
 35 static char sccsid[] = "@(#)qsort.c    8.1 (Berkeley) 6/4/93";
 36 #else
 37 __RCSID("$NetBSD: qsort.c,v 1.21.4.1 2012/10/30 18:58:59 yamt Exp $");
 38 #endif
 39 #endif /* LIBC_SCCS and not lint */
 40 
 41 #include <sys/types.h>
 42 
 43 #include <assert.h>
 44 #include <errno.h>
 45 #include <stdlib.h>
 46 
 47 static inline char    *med3(char *, char *, char *,
 48     int (*)(const void *, const void *));
 49 static inline void     swapfunc(char *, char *, size_t, int);
 50 
 51 #define min(a, b)    (a) < (b) ? a : b
 52 
 53 /*
 54  * Qsort routine from Bentley & McIlroy‘s "Engineering a Sort Function".
 55  */
 56 #define swapcode(TYPE, parmi, parmj, n) {          57     size_t i = (n) / sizeof (TYPE);          58     TYPE *pi = (TYPE *)(void *)(parmi);          59     TYPE *pj = (TYPE *)(void *)(parmj);          60     do {                          61         TYPE    t = *pi;             62         *pi++ = *pj;                 63         *pj++ = t;                 64         } while (--i > 0);                 65 }
 66 
 67 #define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) ||  68     es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
 69 
 70 static inline void
 71 swapfunc(char *a, char *b, size_t n, int swaptype)
 72 {
 73 
 74     if (swaptype <= 1) 
 75         swapcode(long, a, b, n)
 76     else
 77         swapcode(char, a, b, n)
 78 }
 79 
 80 #define swap(a, b)                         81     if (swaptype == 0) {                     82         long t = *(long *)(void *)(a);             83         *(long *)(void *)(a) = *(long *)(void *)(b);     84         *(long *)(void *)(b) = t;             85     } else                             86         swapfunc(a, b, es, swaptype)
 87 
 88 #define vecswap(a, b, n) if ((n) > 0) swapfunc((a), (b), (size_t)(n), swaptype)
 89 
 90 static inline char *
 91 med3(char *a, char *b, char *c,
 92     int (*cmp)(const void *, const void *))
 93 {
 94 
 95     return cmp(a, b) < 0 ?
 96            (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
 97               :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
 98 }
 99 
100 void
101 qsort(void *a, size_t n, size_t es,
102     int (*cmp)(const void *, const void *))
103 {
104     char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
105     size_t d, r;
106     int swaptype, cmp_result;
107 
108     _DIAGASSERT(a != NULL || n == 0 || es == 0);
109     _DIAGASSERT(cmp != NULL);
110 
111 loop:    SWAPINIT(a, es);
112     if (n < 7) {
113         /* For small input, Insertion Sort is more efficient, */
114         for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
115             for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
116                  pl -= es)
117                 swap(pl, pl - es);
118         return;
119     }   /*   otherwise Quicksort is adopted */
120 
121     /* Choose a good pivot and put it at the head of the array;
122      *      larger the input is, more complicated mechanism is exploited. */
123     pm = (char *) a + (n / 2) * es;
124     if (n > 7) {
125         pl = (char *) a;
126         pn = (char *) a + (n - 1) * es;
127         if (n > 40) {
128             d = (n / 8) * es;
129             pl = med3(pl, pl + d, pl + 2 * d, cmp);
130             pm = med3(pm - d, pm, pm + d, cmp);
131             pn = med3(pn - 2 * d, pn - d, pn, cmp);
132         }
133         pm = med3(pl, pm, pn, cmp);
134     }
135     swap(a, pm);
136 
137     /* Loop for Partition: */
138     pa = pb = (char *) a + es;
139     pc = pd = (char *) a + (n - 1) * es;
140     for (;;) {
141         /*  [a,pa) are equal to the pivot;
142          *  [pa,pb) are smaller than the pivot;
143          *  [pb,pc] are unknown elements;
144          *  (pc,pd] are larger than the pivot;
145          *  (pd,pn) are equal to the pivot*/
146         while (pb <= pc && (cmp_result = cmp(pb, a)) <= 0) {
147             /* search from left to right for the 1st element 
148              *      larger than the pivot */
149             if (cmp_result == 0) {
150                 swap(pa, pb);
151                 pa += es;
152             }
153             pb += es;
154         }
155         while (pb <= pc && (cmp_result = cmp(pc, a)) >= 0) {
156             /* search from right to left for the 1st element
157              *      smaller than the pivot */
158             if (cmp_result == 0) {
159                 swap(pc, pd);
160                 pd -= es;
161             }
162             pc -= es;
163         }
164         if (pb > pc)
165             break;
166         swap(pb, pc);
167         pb += es;
168         pc -= es;
169     }
170     pn = (char *) a + n * es;
171     r = min(pa - (char *) a, pb - pa);
172     vecswap(a, pb - r, r);
173     r = min((size_t)(pd - pc), pn - pd - es);
174     vecswap(pb, pn - r, r);
175     /* [a,a+pb-pa) is smaller than the pivot
176      * [a+pb-pa,pn-pd+pc) is equal to the pivot
177      * [pn-pd+pc,pn) is larger than the pivot */
178 
179     /* Divide and Conquer: */
180     if ((r = pb - pa) > es)
181         /* recursion for left part [a, a+pb-a) */
182         qsort(a, r / es, es, cmp);
183     if ((r = pd - pc) > es) { 
184         /* Iterate rather than recurse to save stack space */
185         a = pn - r;
186         n = r / es;
187         goto loop;
188     }   /* qsort(pn - r, r / es, es, cmp); */
189 }

 

 

References:

  1. NetBSD stdlib源码:http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/

 

Binary Search and Quicksort

标签:

原文地址:http://www.cnblogs.com/DevinZ/p/4670754.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!