Binary Search and Quicksort

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/

时间: 2024-08-02 14:30:21

Binary Search and Quicksort的相关文章

[LeetCode] Find Mode in Binary Search Tree 找二分搜索数的众数

Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequently occurred element) in the given BST. Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than or equal to the nod

235. Lowest Common Ancestor of a Binary Search Tree

1. 问题描述 Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T th

leetcode 109 Convert Sorted List to Binary Search Tree

题目连接 https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/ Convert Sorted List to Binary Search Tree Description Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. /** * De

Lowest Common Ancestor of a Binary Search Tree

1. Title 235. Lowest Common Ancestor of a Binary Search Tree 2. Http address https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ 3. The question Given a binary search tree (BST), find the lowest common ancestor (LCA) of two

LeetCode 50 Pow(x, n)(Math、Binary Search)(*)

翻译 实现pow(x, n). 原文 Implement pow(x, n). 分析 首先给大家推荐维基百科: zh.wikipedia.org/wiki/二元搜尋樹 en.wikipedia.org/wiki/Binary_search_tree 其次,大家也可以看看类似的一道题: LeetCode 69 Sqrt(x)(Math.Binary Search)(*) 然而这题我还是没有解出来,看看别人的解法-- class Solution { private: double myPowHel

LeetCode OJ :Unique Binary Search Trees II(唯一二叉搜索树)

题目如下所示:返回的结果是一个Node的Vector: Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. For example,Given n = 3, your program should return all 5 unique BST's shown below. 1 3 3 2 1 \ / / / \ 3 2 1 1 3 2 / / \ 2 1 2

[LeetCode]Validate Binary Search Tree

Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than the node's key. The right subtree of a node contains only nodes with keys

Binary Search Tree Iterator

QUESTION Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST. Calling next() will return the next smallest number in the BST. Note: next() and hasNext() should run in average O(1) time

LeetCode: Validata Binary Search Tree

LeetCode: Validata Binary Search Tree Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than the node's key. The right subtree o