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

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

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

 /*
* Find the Kth Node in BST, K = 1, 2, ...
*/
int
bst_findKthNode(bst_node_t *root, key_t *key, unsigned int k)
{
if (root == NULL)
return -; if (root->left != NULL && k > )
k = bst_findKthNode(root->left, key, k); if (--k == ) {
*key = root->key;
return ;
} if (root->right != NULL && k > )
k = bst_findKthNode(root->right, key, k); return k;
}

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

 /*
* Find the Kth Node in BST, K = 1, 2, ...
*/
bst_node_t *
bst_findKthNode(bst_node_t *root, unsigned int k)
{
bst_node_t *kp = NULL; if (root == NULL)
return NULL; (void) stack_init(STACK_SIZE); while (root != NULL || !stack_isEmpty()) {
if (root != NULL) {
push((uintptr_t)root);
root = root->left;
continue;
} pop((uintptr_t *)(&root));
if (--k == ) {
kp = root;
break;
} root = root->right;
} stack_fini(); return kp;
}

使用Meld进行diff后的截图,

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

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

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

 #ifndef _LIBBST_H
#define _LIBBST_H #ifdef __cplusplus
extern "C" {
#endif #define STACK_SIZE 16 typedef int key_t; typedef struct bst_node_s {
key_t key;
struct bst_node_s *left;
struct bst_node_s *right;
} bst_node_t; int bst_init(bst_node_t **root, key_t a[], size_t n);
void bst_fini(bst_node_t *root);
void bst_walk(bst_node_t *root);
bst_node_t *bst_findKthNode(bst_node_t *root, unsigned int k); #ifdef __cplusplus
}
#endif #endif /* _LIBBST_H */

o libbst.c

 #include <stdio.h>
#include <stdlib.h>
#include "libbst.h"
#include "libstack.h" static int bst_add_node(bst_node_t **root, key_t key); int
bst_init(bst_node_t **root, key_t a[], size_t n)
{
*root = NULL;
for (int i = ; i < n; i++) {
if (bst_add_node(root, a[i]) != )
return -;
} return ;
} #define UMEM_FREE_PATTERN 0xdeadbeefdeadbeefULL
static inline void
BST_DESTROY_NODE(bst_node_t *p)
{
p->left = NULL;
p->right = NULL;
*(unsigned long long *)p = UMEM_FREE_PATTERN;
} void
bst_fini(bst_node_t *root)
{
if (root == NULL)
return; bst_fini(root->left);
bst_fini(root->right); BST_DESTROY_NODE(root);
free(root);
} static int
bst_add_node(bst_node_t **root, key_t key)
{
bst_node_t *leaf = NULL;
leaf = (bst_node_t *)malloc(sizeof (bst_node_t));
if (leaf == NULL) {
fprintf(stderr, "failed to malloc\n");
return -;
} /* init leaf node */
leaf->key = key;
leaf->left = NULL;
leaf->right = NULL; /* add leaf node to root */
if (*root == NULL) { /* root node does not exit */
*root = leaf;
} else {
bst_node_t **pp = NULL;
while () {
if (leaf->key < (*root)->key)
pp = &((*root)->left);
else
pp = &((*root)->right); if (*pp == NULL) {
*pp = leaf;
break;
} root = pp;
}
} return ;
} void
bst_walk(bst_node_t *root)
{
if (root == NULL)
return; (void) stack_init(STACK_SIZE); while (root != NULL || !stack_isEmpty()) {
if (root != NULL) {
push((uintptr_t)root);
root = root->left;
continue;
} pop((uintptr_t *)(&root));
printf("%d\n", root->key); root = root->right;
} stack_fini();
} /*
* Find the Kth Node in BST, K = 1, 2, ...
*/
bst_node_t *
bst_findKthNode(bst_node_t *root, unsigned int k)
{
bst_node_t *kp = NULL; if (root == NULL)
return NULL; (void) stack_init(STACK_SIZE); while (root != NULL || !stack_isEmpty()) {
if (root != NULL) {
push((uintptr_t)root);
root = root->left;
continue;
} pop((uintptr_t *)(&root));
if (--k == ) {
kp = root;
break;
} root = root->right;
} stack_fini(); return kp;
}

o foo.c (简单测试)

 #include <stdio.h>
#include <stdlib.h>
#include "libbst.h" int
main(int argc, char *argv[])
{
if (argc != ) {
fprintf(stderr, "Usage: %s <Kth>\n", argv[]);
return -;
} int a[] = {, , , , , , , , };
int n = sizeof (a) / sizeof (int); bst_node_t *root = NULL;
bst_init(&root, a, n); bst_walk(root); unsigned int k = atoi(argv[]);
bst_node_t *p = NULL;
if ((p = bst_findKthNode(root, k)) == NULL) {
printf("\nOops, the %dth node not found\n", k);
goto done;
}
printf("\nWell, the %dth node found, its key is %d\n", k, p->key); done:
bst_fini(root); return ;
}

o Makefile

 CC    = gcc
CFLAGS = -g -Wall -std=gnu99 -m32
INCS = TARGET = foo all: ${TARGET} foo: foo.o libstack.o libbst.o
${CC} ${CFLAGS} -o $@ $^ foo.o: foo.c
${CC} ${CFLAGS} -c $< ${INCS} libstack.o: libstack.c libstack.h
${CC} ${CFLAGS} -c $< libbst.o: libbst.c libbst.h
${CC} ${CFLAGS} -c $< clean:
rm -f *.o
clobber: clean
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 Well, the 6th node found, its key is $ ./foo | 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: 数据流中的中位数

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

  1. C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解

    剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...

  2. 萌新笔记之二叉搜索树(BST)

    前言,以前搞过线段树,二叉树觉得也就那样= =.然后数据结构的课也没怎么听过,然后下周期中考... 本来以为今天英语考完可以好好搞ACM了,然后这个数据结构期中考感觉会丢人,还是好好学习一波. 二叉搜 ...

  3. 二叉搜索树(BST)---python实现

    github:代码实现 本文算法均使用python3实现 1. 二叉搜索树定义   二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree).   二叉搜 ...

  4. 给定一个二叉搜索树(BST),找到树中第 K 小的节点

    问题:给定一个二叉搜索树(BST),找到树中第 K 小的节点. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深技术专家. 考察点: 1. 基础数据结构的理解和编码能力 2.  递归使用 参考答案 ...

  5. 二叉搜索树 (BST) 的创建以及遍历

    二叉搜索树(Binary Search Tree) : 属于二叉树,其中每个节点都含有一个可以比较的键(如需要可以在键上关联值), 且每个节点的键都大于其左子树中的任意节点而小于右子树的任意节点的键. ...

  6. 二叉搜索树(BST)学习笔记

    BST调了一天,最后遍历参数错了,没药救了-- 本文所有代码均使用数组+结构体,不使用指针! 前言--BFS是啥 BST 二叉搜索树是基于二叉树的一种树,一种特殊的二叉树. 二叉搜索树要么是一颗空树, ...

  7. 二叉搜索树(BST)

    (第一段日常扯蛋,大家不要看)这几天就要回家了,osgearth暂时也不想弄了,毕竟不是几天就能弄出来的,所以打算过完年回来再弄.这几天闲着也是闲着,就掏出了之前买的算法导论看了看,把二叉搜索树实现了 ...

  8. hdu 3791:二叉搜索树(数据结构,二叉搜索树 BST)

    二叉搜索树 Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submiss ...

  9. 数据结构---二叉搜索树BST实现

    1. 二叉查找树 二叉查找树(Binary Search Tree),也称为二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一 ...

随机推荐

  1. Amazon前技术副总裁解剖完美技术面试

    Amazon前技术副总裁解剖完美技术面试 投递人 itwriter 发布于 2014-03-03 14:30 评论(0) 有1729人阅读  原文链接  [收藏]  « » 英文原文:The Anat ...

  2. mvc3项目如何在IIS7.5上发布的

    若项目拿到服务器上发布,必须要安装MVC3的安装包! 1.在vs中打开你要发布的项目,右键属性找到发布 2.弹出发布web对话框,选择<新建配置文件...> 在弹出的对话框中输入一个配置文 ...

  3. MS SQL优化

    数据库优化实践[MS SQL优化开篇]   数据库定义: 数据库是依照某种数据模型组织起来并存在二级存储器中的数据集合,此集合具有尽可能不重复,以最优方式为特定组织提供多种应用服务,其数据结构独立于应 ...

  4. 网络地址到物理地址的映射(ARP)

    网络的互连首先要解决的问题就是网络地址到物理地址的映射,以太网接口分配的是一个48位的物理地址,而IP地址却只有32位,因此无法将它编码到IP地址中.有人建议可以构建一个中央数据库存储所有网络中的网络 ...

  5. Model 验证

    [ASP.NET MVC 小牛之路]16 - Model 验证 上一篇博文 [ASP.NET MVC 小牛之路]15 - Model Binding 中讲了MVC在Model Binding过程中如何 ...

  6. PHP gbk转换成utf8

    /** * GBK ASCII 转换成utf8 */ public function to_utf8($str){ $detect = array('ASCII', 'GBK', 'UTF-8'); ...

  7. z-index 解析

    很多人对z-index的认识仅止于:z-index是控制元素在页面中的堆叠顺序,z-index值高的元素显示在z-index值低的前面.而其中的原因才很少有人去深究,直到自己在实际项目中碰到由于z-i ...

  8. NSSortDescriptor(数组排序)

    如果数组里面的每一个元素都是一个个model,例如 DepartsDate.h文件 [plain] view plaincopy #import <Foundation/Foundation.h ...

  9. AJAX异步提交,浏览器总跳出下载界面

    问题: 我在写一个网页的“用户登录”部分时,要将用户名和密码传到后端验证,想在前端用了AJAX异步提交功能,将 用户名密码传到后端,然后后端返回验证结果.但AJAX写好后每次刷新网页都会跳出下载窗口, ...

  10. URL 调度器(URL dispatcher)

    URL 调度器(URL dispatcher) 在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 UR ...