在二叉搜索树(BST)中查找第K个大的结点之非递归实现
一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第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个大的结点之非递归实现的更多相关文章
- C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解
剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...
- 萌新笔记之二叉搜索树(BST)
前言,以前搞过线段树,二叉树觉得也就那样= =.然后数据结构的课也没怎么听过,然后下周期中考... 本来以为今天英语考完可以好好搞ACM了,然后这个数据结构期中考感觉会丢人,还是好好学习一波. 二叉搜 ...
- 二叉搜索树(BST)---python实现
github:代码实现 本文算法均使用python3实现 1. 二叉搜索树定义 二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree). 二叉搜 ...
- 给定一个二叉搜索树(BST),找到树中第 K 小的节点
问题:给定一个二叉搜索树(BST),找到树中第 K 小的节点. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深技术专家. 考察点: 1. 基础数据结构的理解和编码能力 2. 递归使用 参考答案 ...
- 二叉搜索树 (BST) 的创建以及遍历
二叉搜索树(Binary Search Tree) : 属于二叉树,其中每个节点都含有一个可以比较的键(如需要可以在键上关联值), 且每个节点的键都大于其左子树中的任意节点而小于右子树的任意节点的键. ...
- 二叉搜索树(BST)学习笔记
BST调了一天,最后遍历参数错了,没药救了-- 本文所有代码均使用数组+结构体,不使用指针! 前言--BFS是啥 BST 二叉搜索树是基于二叉树的一种树,一种特殊的二叉树. 二叉搜索树要么是一颗空树, ...
- 二叉搜索树(BST)
(第一段日常扯蛋,大家不要看)这几天就要回家了,osgearth暂时也不想弄了,毕竟不是几天就能弄出来的,所以打算过完年回来再弄.这几天闲着也是闲着,就掏出了之前买的算法导论看了看,把二叉搜索树实现了 ...
- hdu 3791:二叉搜索树(数据结构,二叉搜索树 BST)
二叉搜索树 Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submiss ...
- 数据结构---二叉搜索树BST实现
1. 二叉查找树 二叉查找树(Binary Search Tree),也称为二叉搜索树.有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一 ...
随机推荐
- SQLSERVER数据库学习总结七(视图,索引)
--视图的主意点:不能和表的名称相同,如果某一列为函数,表达式,常量或者与来自多张表的列名相同,必须为列定义名称,不能在试图上创建索引 if exists(select 1 from sys.syso ...
- window wamp下xhprof的安装使用,Graphviz配置
在新的工作安排下来前赶紧把手上工作优化下,本来是靠xdebug+grindview来的,不过还是麻烦,就换上这个轻量级的性能测试了.网上搜的大多都是lamp环境下的,wamp下的倒是不多,而且不好用, ...
- Github官方app分析——用户身份验证模块
这篇文章记述的是我对Giuhub官方app的用户身份验证模块的分析. Giuhub的官方app虽然是一个非常小众的程序,但是从程序的设计的角度看,这是一个非常优秀的项目.对于其用户身份验证模块,给我留 ...
- K-Means算法
K-Means算法 K-Means算法的输入N,K和一个size为N的向量组vector.输出K个两两互不相交的向量组.其本质是将给定的向量组划分成K个类别,使得同类别的向量相似度比较大,而不同类别的 ...
- 第一个python
import MySQLdb import os,sys import string dto=os.getcwd()+"\\dto" dao=os.getcwd()+"\ ...
- Jquery 类似新浪微博,鼠标移到头像,用浮动窗口显示用户信息,已做成一个jquery插件
请注意!!!!! 该插件demo PHP 的 demo下载 C#.NET的demo下载 需要如下图, 1.鼠标移动到头像DIV时,Ajax获取数据,并让浮动DIV显示出来. 2.鼠标可以移动到上面浮 ...
- 一个使用MVC3+NHibernate “增删改查” 的项目
一个使用MVC3+NHibernate “增删改查” 的项目 前言: 谈到NHibernate大伙并不陌生,搞Java的更是清楚,Hibernate是一个目前应用的最广泛的开放源代码的对象关系映射框 ...
- JS左侧菜单-04
<script language="javascript" type="text/javascript"> function HideShow() ...
- [解决]Windows Server 2012 不能安装IE版的Flash
1.问题描述 在server 2012下安装IE版的Flash提示包含最新版本 2.解决方法 2.1.开启“桌面体验”功能 2.2.关闭“IE增强的安全配置”功能 3.重启计算机后安装Flash
- win7 安装 sql2000
win7 安装:http://wenku.baidu.com/link?url=xNcfrMaMzX0KgBcjpMaySRaKITM2Op73ZI8sOX49zgl-GWPGB3vqye9gZA_c ...