一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第K个大的结点。

PS:我第一次在面试的时候被问到这个问题而且让我直接在白纸上写的时候,直接蒙圈了,因为没有刷题准备,所以就会有伤害。知耻而后勇,于是我回家花了两个半小时(在不参考任何书本和网路上的源码的前提下),从构建BST开始,到实现中序遍历,最后用递归方法写出bst_findKthNode()并用gdb调试成功。 不过,使用递归实现这个实在是比较low,所以这个周末我决定用非递归方法实现。

先贴一下我的递归实现 (个人觉得比较low, 虽然实现了,但是不满意)

 1 /*
 2  * Find the Kth Node in BST, K = 1, 2, ...
 3  */
 4 int
 5 bst_findKthNode(bst_node_t *root, key_t *key, unsigned int k)
 6 {
 7         if (root == NULL)
 8                 return -1;
 9
10         if (root->left != NULL && k > 0)
11                 k = bst_findKthNode(root->left, key, k);
12
13         if (--k == 0) {
14                 *key = root->key;
15                 return 0;
16         }
17
18         if (root->right != NULL && k > 0)
19                 k = bst_findKthNode(root->right, key, k);
20
21         return k;
22 }

下面的代码是我写的非递归实现。

 1 /*
 2  * Find the Kth Node in BST, K = 1, 2, ...
 3  */
 4 bst_node_t *
 5 bst_findKthNode(bst_node_t *root, unsigned int k)
 6 {
 7         bst_node_t *kp = NULL;
 8
 9         if (root == NULL)
10                 return NULL;
11
12         (void) stack_init(STACK_SIZE);
13
14         while (root != NULL || !stack_isEmpty()) {
15                 if (root != NULL) {
16                         push((uintptr_t)root);
17                         root = root->left;
18                         continue;
19                 }
20
21                 pop((uintptr_t *)(&root));
22                 if (--k == 0) {
23                         kp = root;
24                         break;
25                 }
26
27                 root = root->right;
28         }
29
30         stack_fini();
31
32         return kp;
33 }

使用Meld进行diff后的截图,

注意: 题目请参见《剑指Offer》(何海涛著)面试题63: 二叉搜索树的第k个结点, 其cpp答案在这里。

最后,贴出完整的代码和测试运行结果。

o libstack.h 和 libstack.c (参见 将递归函数非递归化的一般方法(cont) 一文)
o libbst.h

 1 #ifndef _LIBBST_H
 2 #define _LIBBST_H
 3
 4 #ifdef    __cplusplus
 5 extern "C" {
 6 #endif
 7
 8 #define STACK_SIZE 16
 9
10 typedef int key_t;
11
12 typedef struct bst_node_s {
13     key_t key;
14     struct bst_node_s *left;
15     struct bst_node_s *right;
16 } bst_node_t;
17
18 int bst_init(bst_node_t **root, key_t a[], size_t n);
19 void bst_fini(bst_node_t *root);
20 void bst_walk(bst_node_t *root);
21 bst_node_t *bst_findKthNode(bst_node_t *root, unsigned int k);
22
23 #ifdef    __cplusplus
24 }
25 #endif
26
27 #endif /* _LIBBST_H */

o libbst.c

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include "libbst.h"
  4 #include "libstack.h"
  5
  6 static int bst_add_node(bst_node_t **root, key_t key);
  7
  8 int
  9 bst_init(bst_node_t **root, key_t a[], size_t n)
 10 {
 11     *root = NULL;
 12     for (int i = 0; i < n; i++) {
 13         if (bst_add_node(root, a[i]) != 0)
 14             return -1;
 15     }
 16
 17     return 0;
 18 }
 19
 20 #define UMEM_FREE_PATTERN 0xdeadbeefdeadbeefULL
 21 static inline void
 22 BST_DESTROY_NODE(bst_node_t *p)
 23 {
 24     p->left = NULL;
 25     p->right = NULL;
 26     *(unsigned long long *)p = UMEM_FREE_PATTERN;
 27 }
 28
 29 void
 30 bst_fini(bst_node_t *root)
 31 {
 32     if (root == NULL)
 33         return;
 34
 35     bst_fini(root->left);
 36     bst_fini(root->right);
 37
 38     BST_DESTROY_NODE(root);
 39     free(root);
 40 }
 41
 42 static int
 43 bst_add_node(bst_node_t **root, key_t key)
 44 {
 45     bst_node_t *leaf = NULL;
 46     leaf = (bst_node_t *)malloc(sizeof (bst_node_t));
 47     if (leaf == NULL) {
 48         fprintf(stderr, "failed to malloc\n");
 49         return -1;
 50     }
 51
 52     /* init leaf node */
 53     leaf->key   = key;
 54     leaf->left  = NULL;
 55     leaf->right = NULL;
 56
 57     /* add leaf node to root */
 58     if (*root == NULL) { /* root node does not exit */
 59         *root = leaf;
 60     } else {
 61         bst_node_t **pp = NULL;
 62         while (1) {
 63             if (leaf->key < (*root)->key)
 64                 pp = &((*root)->left);
 65             else
 66                 pp = &((*root)->right);
 67
 68             if (*pp == NULL) {
 69                 *pp = leaf;
 70                 break;
 71             }
 72
 73             root = pp;
 74         }
 75     }
 76
 77     return 0;
 78 }
 79
 80 void
 81 bst_walk(bst_node_t *root)
 82 {
 83     if (root == NULL)
 84         return;
 85
 86     (void) stack_init(STACK_SIZE);
 87
 88     while (root != NULL || !stack_isEmpty()) {
 89         if (root != NULL) {
 90             push((uintptr_t)root);
 91             root = root->left;
 92             continue;
 93         }
 94
 95         pop((uintptr_t *)(&root));
 96         printf("%d\n", root->key);
 97
 98         root = root->right;
 99     }
100
101     stack_fini();
102 }
103
104 /*
105  * Find the Kth Node in BST, K = 1, 2, ...
106  */
107 bst_node_t *
108 bst_findKthNode(bst_node_t *root, unsigned int k)
109 {
110     bst_node_t *kp = NULL;
111
112     if (root == NULL)
113         return NULL;
114
115     (void) stack_init(STACK_SIZE);
116
117     while (root != NULL || !stack_isEmpty()) {
118         if (root != NULL) {
119             push((uintptr_t)root);
120             root = root->left;
121             continue;
122         }
123
124         pop((uintptr_t *)(&root));
125         if (--k == 0) {
126             kp = root;
127             break;
128         }
129
130         root = root->right;
131     }
132
133     stack_fini();
134
135     return kp;
136 }

o foo.c (简单测试)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "libbst.h"
 4
 5 int
 6 main(int argc, char *argv[])
 7 {
 8     if (argc != 2) {
 9         fprintf(stderr, "Usage: %s <Kth>\n", argv[0]);
10         return -1;
11     }
12
13     int a[] = {30, 10, 40, 20, 50, 80, 70, 60, 90};
14     int n = sizeof (a) / sizeof (int);
15
16     bst_node_t *root = NULL;
17     bst_init(&root, a, n);
18
19     bst_walk(root);
20
21     unsigned int k = atoi(argv[1]);
22     bst_node_t *p = NULL;
23     if ((p = bst_findKthNode(root, k)) == NULL) {
24         printf("\nOops, the %dth node not found\n", k);
25         goto done;
26     }
27     printf("\nWell, the %dth node found, its key is %d\n", k, p->key);
28
29 done:
30     bst_fini(root);
31
32     return 0;
33 }

o Makefile

 1 CC    = gcc
 2 CFLAGS    = -g -Wall -std=gnu99 -m32
 3 INCS    =
 4
 5 TARGET    = foo
 6
 7 all: ${TARGET}
 8
 9 foo: foo.o libstack.o libbst.o
10     ${CC} ${CFLAGS} -o $@ $^
11
12 foo.o: foo.c
13     ${CC} ${CFLAGS} -c $< ${INCS}
14
15 libstack.o: libstack.c libstack.h
16     ${CC} ${CFLAGS} -c $<
17
18 libbst.o: libbst.c libbst.h
19     ${CC} ${CFLAGS} -c $<
20
21 clean:
22     rm -f *.o
23 clobber: clean
24     rm -f ${TARGET}

o 编译并测试运行

$ make
gcc -g -Wall -std=gnu99 -m32 -c foo.c
gcc -g -Wall -std=gnu99 -m32 -c libstack.c
gcc -g -Wall -std=gnu99 -m32 -c libbst.c
gcc -g -Wall -std=gnu99 -m32 -o foo foo.o libstack.o libbst.o$ ./foo 6
10
20
30
40
50
60
70
80
90Well, the 6th node found, its key is 60$ ./foo 16 | egrep 'Oops,'
Oops, the 16th node not found
$

扩展题目: "寻找两个数组的中位数"。 题目描述如下:

有两个数组, 第一个数组a里的元素按照升序排列, e.g. int a[] = {10, 30, 40, 70, 80, 90};

第二个数组b里的元素按照降序排列, e.g. int b[] = {60, 50, 30, 20, 10};

请寻找数组a和b的合集的中位数,e.g. 50。

解决方案:

  • 使用数组a构建一个无重复key的BST
  • 将数组b里的元素加入BST (若某个元素已经在BST中存在,不予加入)
  • 设BST中的所有结点总数为N (a) 若N为偶数, 查找第K, K+1个元素 (K=N/2) 并求其平均值; (b) 若N为奇数, 查找第K+1个元素(K=N/2)。

关于此题目的详细描述和解决方案请参见 《剑指Offer》(何海涛著)面试题64: 数据流中的中位数。

转载于:https://www.cnblogs.com/idorax/p/6288719.html

在二叉搜索树(BST)中查找第K个大的结点之非递归实现相关推荐

  1. PAT甲级1043 Is It a Binary Search Tree :[C++题解]判断二叉搜索树BST、给定前序序列和中序序列

    文章目录 题目分析 题目链接 题目分析 二叉搜索树(BST):左子树小于根结点,右子树大于等于根结点. 二叉搜索树的中序遍历一定是有序序列.所谓中序遍历:先访问左子树,再访问根结点,最后访问右子树. ...

  2. 二叉搜索树 (BST)

    二叉搜索树 (BST : Binary Search Tree) 又名 二叉查找树 或 二叉排序树. 二叉搜索树: 左孩子的值 一定小于或等于 父结点的值 二叉搜索树: 右孩子的值 一定大于或等于 父 ...

  3. 二叉搜索树BST的学习

    文章目录 二叉搜索树BST 什么是BST? 用BST做什么? 一.BST的特性 BST的特性是什么? 1.[230. 二叉搜索树中第K小的元素](https://leetcode.cn/problem ...

  4. 真c++ 从二叉树到红黑树(3)之二叉搜索树BST

      此文章为从二叉树到红黑树系列文章的第三节,主要介绍介绍二叉搜索树BST,为AVL和RedBlack打下基础 文章目录 一.前面文章链接~(点击右边波浪线可以返回目录) 二.二叉搜索树BST的定义~ ...

  5. 二叉搜索树——插入、查找、删除

    二叉搜索树 二叉搜索树的特点 根节点的值大于左结点的值,小于右结点的值 根节点的左.右子树也是一个二叉搜索树 没有重复值 中序遍历得到的序列是从小到大排列的 二叉树的存储结构 typedef stru ...

  6. 二叉搜索树(BST的理论剖析+代码实现)

    二叉搜索树(BST树) 文章目录 二叉搜索树(BST树) 1.二叉搜索树的概念 2.二叉搜索树的结构定义 2.1 二叉搜索树结点模板的定义 2.2 二叉搜索树类模板的定义 3.二叉搜索树的效率 4.二 ...

  7. 五.树,二叉树,二叉搜索树(BST)和自平衡二叉搜索树(AVL)

    1.树 树是一种数据结构 比如:目录结构 树是一种可以递归定义的数据结构 树是由n个节点组成的集合: 如果 n=0, 那这是一颗空树 如果 n>0, 那存在1个节点作为树的根节点,其他节点可以分 ...

  8. 二叉搜索树BST红黑树

    二叉搜索树基础知识 提起红黑树咱们肯定要先说说这个二叉搜索树(BST) 二叉搜索树又叫二叉查找树,二叉排序树:它具有以下特点: 如果它的左子树不为空,则左子树上结点的值都小于根结点. 如果它的右子树不 ...

  9. PAT甲级1064 Complete Binary Search Tree (30分):[C++题解]完全二叉搜索树BST

    文章目录 题目分析 题目链接 题目分析 思路: 第一步,构造含有n个结点的完全二叉树:第二步,将n个数值填入,使其满足二叉搜索树的性质. 对于第一步: 完全二叉树用一维数组可以存下,不过从根结点的下标 ...

最新文章

  1. Android10.0应用进程创建过程以及Zygote的fork流程-[Android取经之路]
  2. 姚班系创业公司宸镜科技再获新融资,漆子超、陈启峰联手,OPPO入股加持“元宇宙”概念要火?...
  3. 获取内容第一张图片地址的函数
  4. 分区表的本地索引竟然失效了——ORA-01502
  5. MySQL 基本数据类型
  6. ThinkPHP采用模块和操作
  7. 10.cadence.自定义焊盘的创建[原创]
  8. 嵌入式系统——文件系统
  9. python爬取某鱼的直播间信息
  10. 银河麒麟安装Redis 6.0.3
  11. compute shader
  12. Nginx介绍及安装配置
  13. 刨根系列之volatile详解
  14. 数学建模竞赛赛前准备及资源分享
  15. JAVA中用POI操作word
  16. IOS 定位 CLLocationManager
  17. 苹果手表的真实触感信息(Real Touch Messaging)
  18. 台式计算机负荷,简单计算台式电脑功率
  19. 2022android自定义文本路径选择器java教程
  20. 当你学会炒菜的时候,你就学会了大数据

热门文章

  1. mysql数学函数有什么_mysql数学函数有哪些?
  2. 2018-01-17
  3. 学术英语视听说2听力原文_做英语听力题有哪些非常实用的小技巧?
  4. 如何在GO语言中使用Kubernetes API?
  5. 挂载本地目录到Virtualbox并解决[mounting failed with the error: Protocol error]错误
  6. AIR:使用 HTML + Javascript 开发桌面应用
  7. DXUT框架剖析(4)
  8. 典型的异步客户端套接字构建
  9. Android已读未读功能,Android实现小圆点显示未读功能
  10. pycharm python3.7环境_Python3+Pycharm+PyQt5环境搭建步骤图文详解