表转化成平衡二叉树

其中有一种分治的思想。

(define (list->tree elements)
(define (partial-tree elts n)
(if (= n 0)
(cons '() elts)
(let ((left-size (quotient (- n 1) 2)))
(let ((left-result (partial-tree elts left-size)))
(let ((left-tree (car left-result))
(non-left-elts (cdr left-result))
(right-size (- n (+ left-size 1))))
(let ((this-entry (car non-left-elts))
(right-result (partial-tree (cdr non-left-elts) right-size)))
(let ((right-tree (car right-result))
(remaining-elts (cdr right-result)))
(cons (make-tree this-entry left-tree right-tree) remaining-elts))))))))
(car (partial-tree elements (length elements))))
(display (list->tree '(3 1 2 4 1 2)))

二叉查找树实现集合

#lang planet neil/sicp

(define (entry tree) (car tree))

(define (left-branch tree) (cadr tree))

(define (right-branch tree) (caddr tree))

(define (make-tree entry left right)
(list entry left right)) (define (element-of-tree? x tree)
(cond ((null? tree) #f)
((= x (entry tree)) #t)
((< x (entry tree)) (element-of-tree? x (left-branch tree)))
((> x (entry tree)) (element-of-tree? x (right-branch tree))))) (define (adjoin-tree x tree)
(cond ((null? tree) (make-tree x '() '()))
((= x (entry tree)) tree)
((< x (entry tree))
(make-tree (entry tree) (adjoin-tree x (left-branch tree)) (right-branch tree)))
((> x (entry tree))
(make-tree (entry tree) (left-branch tree) (adjoin-tree x (right-branch tree)))))) (define (delete-tree x tree)
(define (find-max tree)
(if (and (null? (left-branch tree)) (null? (right-branch tree)))
(entry tree)
(find-max (right-branch tree))))
(define (dlt x tree)
(if (null? tree)
'()
(if (= (entry tree) x)
(let ((left (left-branch tree)) (right (right-branch tree)))
(cond ((and (null? left) (null? right)) '())
((null? left) right)
((null? right) left)
(else
(let ((mx (find-max left)))
(make-tree mx (dlt mx left) right)))))
(make-tree (entry tree) (dlt x (left-branch tree)) (dlt x (right-branch tree))))))
(if (element-of-tree? x tree)
(dlt x tree)
tree)) (define (tree->list tree)
(define (copy-to-list tree result-list)
(if (null? tree)
result-list
(copy-to-list (left-branch tree)
(cons (entry tree)
(copy-to-list (right-branch tree)
result-list)))))
(copy-to-list tree '())) (define (list->tree elements)
(define (partial-tree elts n)
(if (= n 0)
(cons '() elts)
(let ((left-size (quotient (- n 1) 2)))
(let ((left-result (partial-tree elts left-size)))
(let ((left-tree (car left-result))
(non-left-elts (cdr left-result))
(right-size (- n (+ left-size 1))))
(let ((this-entry (car non-left-elts))
(right-result (partial-tree (cdr non-left-elts) right-size)))
(let ((right-tree (car right-result))
(remaining-elts (cdr right-result)))
(cons (make-tree this-entry left-tree right-tree) remaining-elts))))))))
(car (partial-tree elements (length elements)))) (define (union-tree tree1 tree2)
(define (union-list list1 list2)
(cond ((null? list1) list2)
((null? list2) list1)
((< (car list1) (car list2))
(cons (car list1) (union-list (cdr list1) list2)))
((< (car list2) (car list1))
(cons (car list2) (union-list (cdr list2) list1)))
((= (car list1) (car list2))
(cons (car list1) (union-list (cdr list1) (cdr list2))))))
(list->tree (union-list (tree->list tree1) (tree->list tree2)))) (define (intersection-tree tree1 tree2)
(define (intersection-list list1 list2)
(cond ((or (null? list1) (null? list2)) '())
((< (car list1) (car list2))
(intersection-list (cdr list1) list2))
((< (car list2) (car list1))
(intersection-list (cdr list2) list1))
((= (car list1) (car list2))
(cons (car list1) (intersection-list (cdr list1) (cdr list2))))))
(list->tree (intersection-list (tree->list tree1) (tree->list tree2)))) (define (getlist n MAX)
(if (= n 0)
'()
(cons (random MAX) (getlist (- n 1) MAX)))) (define (list->BST lst)
(if (null? lst)
'()
(adjoin-tree (car lst) (list->BST (cdr lst)))))

注:

  • list->treetree->list行为恰好相反。
  • 树转化成表是从右往左放数。
  • 最大的值一定是树最右边的结点,而这个结点正好在转化成表的时候处于表的最右端,保证了转化成的表的有序性(当然前提树是二叉查找树)。
  • 要想通过list->tree得到一棵二叉查找树,必须保证是有序表。

添加、删除操作

(define tree '())
(set! tree (adjoin-tree 3 tree))
(set! tree (adjoin-tree 1 tree))
(set! tree (adjoin-tree 5 tree))
(set! tree (adjoin-tree 8 tree))
(set! tree (adjoin-tree 9 tree))
(set! tree (adjoin-tree 7 tree))
(set! tree (adjoin-tree 2 tree))
(set! tree (adjoin-tree 4 tree))
(set! tree (adjoin-tree 11 tree))
(display tree) (newline)
; (3 (1 () (2 () ())) (5 (4 () ()) (8 (7 () ()) (9 () (11 () ()))))) (set! tree (delete-tree 3 tree))
(display tree) (newline)
; (2 (1 () ()) (5 (4 () ()) (8 (7 () ()) (9 () (11 () ()))))) (display (delete-tree 8 tree)) (newline)
; (2 (1 () ()) (5 (4 () ()) (7 () (9 () (11 () ()))))) (display (delete-tree 9 tree)) (newline)
; (2 (1 () ()) (5 (4 () ()) (8 (7 () ()) (11 () ())))) (display (delete-tree 5 tree)) (newline)
; (2 (1 () ()) (4 () (8 (7 () ()) (9 () (11 () ()))))) (set! tree (delete-tree 2 tree))
(display tree) (newline)
; (1 () (5 (4 () ()) (8 (7 () ()) (9 () (11 () ()))))) (display (delete-tree 1 tree)) (newline)
; (5 (4 () ()) (8 (7 () ()) (9 () (11 () ())))) (set! tree (delete-tree 5 tree))
(set! tree (delete-tree 4 tree))
(set! tree (delete-tree 8 tree))
(set! tree (delete-tree 7 tree))
(set! tree (delete-tree 9 tree))
(set! tree (delete-tree 11 tree))
(display tree) (newline)
; (1 () ())
(set! tree (delete-tree 1 tree))
(display tree)
; ()

对两棵二叉查找树取 交、并 操作。

(define list1 (list 1 2 3 9))
(define list2 (list 3 4 7 9))
(define tree1 (list->tree list1))
(define tree2 (list->tree list2))
(display tree1)(newline)
; (2 (1 () ()) (3 () (9 () ())))
(display tree2)(newline)
; (4 (3 () ()) (7 () (9 () ())))
(display (union-tree tree1 tree2))(newline)
; (3 (1 () (2 () ())) (7 (4 () ()) (9 () ())))
(display (intersection-tree tree1 tree2))
; (3 () (9 () ()))

利用上面的函数也可以实现\(O(n+nlogn)\)的排序操作。

(define list1 (getlist 10 10)) ; 生成随机表
(define bst1 (list->BST list1)) ; 转化成二叉查找树
(display list1)(newline)
(display bst1)(newline)
(display (tree->list bst1)) ; 有序表

总结

用 Scheme 实现二叉查找树真的很有意思,首先是代码结构非常紧凑,加上有意义的变量名、函数名会显得更加直观,但是要想一次写好,必须对整个过程进行设计,不然很容易写到后面发现前面有缺漏从而影响全局的代码。

其中一些代码来自于 SICP,自己按照 BST 删除的原理实现了删除的过程。

关于递归的理解更深了一点。首先要明确这个过程到底要做什么?会返回什么值?是什么类型的值?

Scheme实现二叉查找树及基本操作(添加、删除、并、交)的更多相关文章

  1. SQL语句添加删除修改字段及一些表与字段的基本操作

    用SQL语句添加删除修改字段 1.增加字段     alter table docdsp    add dspcode char(200)2.删除字段     ALTER TABLE table_NA ...

  2. 用SQL语句添加删除修改字段、一些表与字段的基本操作、数据库备份等

    用SQL语句添加删除修改字段 1.增加字段 alter table docdsp add dspcode char(200) 2.删除字段 ALTER TABLE table_NAME DROP CO ...

  3. Splay的基本操作(插入/删除,查询)

    Splay的基本操作(插入/删除,查询) 概述 这是一棵二叉查找树 让频繁访问的节点尽量靠近根 将查询,插入等操作的点"旋转"至根 树的高度均摊为$log_n$ 变量 int ro ...

  4. WPF下的Richtextbox中实现表格合并,添加删除行列等功能

    .Net中已有现在的方法实现这些功能,不过可能是由于未完善,未把方法公开出来.只能用反射的方法去调用它. 详细信息可以查看.Net Framework 的源代码 http://referencesou ...

  5. 编辑 Ext 表格(一)——— 动态添加删除行列

    一.动态增删行 在 ext 表格中,动态添加行主要和表格绑定的 store 有关, 通过对 store 数据集进行添加或删除,就能实现表格行的动态添加删除.   (1) 动态添加表格的行  gridS ...

  6. Angular-表单动态添加删除

    angular本身不允许去操作DOM,在angular的角度来说,所有操作都以数据为核心,剩下的事情由angular来完成.所以说,想清楚问题的根源,解决起来也不是那么困难. 前提 那么,要做的这个添 ...

  7. 用Javascript动态添加删除HTML元素实例 (转载)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. [CentOS]添加删除用户

    摘要 在安装CentOS的时候,我们只设置了root,类似windows的超级管理员.当然我们在工作的时候,为了安全考虑,不可能对外开发root,一方面是从安全的角度,另一方面也是方便管理. 添加删除 ...

  9. iOS仿网易新闻栏目拖动重排添加删除效果

    仿网易新闻栏目选择页面的基本效果,今天抽了点时间教大家如何实现UICollectionView拖动的效果! 其实实现起来并不复杂,这里只是基本的功能,没有实现细节上的修改,连UI都是丑丑的样子,随手画 ...

随机推荐

  1. 【vue系列之一】使用vue脚手架工具搭建vue-webpack项目

    对于Vue.js来说,如果你想要快速开始,那么只需要在你的html中引入一个<script>标签,加上CDN的地址即可.但是,这并不算是一个完整的vue实际应用.在实际应用中,我们必须要一 ...

  2. JS中常用的几种时间格式处理-【笔记整理】

    //此处整理点平时常用到的时间格式处理方法 ------------------------------------------- //时间格式化函数 Date.prototype.format = ...

  3. 酷睿彩票合买代购网站管理系统 v2016 - 源码下载 有合买功能 有免费版 标准版 高级版

    源码介绍 免费版下载地址 电信 浙江腾佑 网鼎科技 正易网络下载 联通 网鼎联通   标准版联系QQ:1395239152 彩票合买代购网站管理系统公司独立开发,完全拥有软件自主知识产权.具有电脑We ...

  4. Vbs脚本实现radmin终极后门

    Vbs脚本实现radmin终极后门 代码如下: on error resume next const HKEY_LOCAL_MACHINE = &H80000002 strComputer = ...

  5. Charles Proxy 4.1.2 破解版

    下载Charles Proxy 4.1.2版本,百度云盘下载 或 去官网下载 安装后先打开Charles一次(Windows版可以忽略此步骤) 在这个网站(http://charles.iiilab. ...

  6. bootstrap学习笔记之基础导航条 http://www.imooc.com/code/3111

    基础导航条 在Bootstrap框中,导航条和导航从外观上差别不是太多,但在实际使用中导航条要比导航复杂得多.我们先来看导航条中最基础的一个--基础导航条. 使用方法: 在制作一个基础导航条时,主要分 ...

  7. 【2017-05-21】WebForm内置对象:Session、Cookie,登录和状态保持

    1.Request -获取请求对象 string s =Request["key"]; 2.Response  -  响应请求对象 Response.Redirect(" ...

  8. C语言习题1.分别统计一下其中字母,数字,其他字符的个数。将统计的字母,数字,其他字符的个数以柱状图的形式打印

    从键盘上输入字符,(1)分别统计一下其中字母,数字,其他字符的个数, (2)将统计的字母,数字,其他字符的个数以柱状图的形式打印.例如 5 ***** *****     3 *****   **** ...

  9. ubuntu16.04 英文环境安装中文输入法

    1. 安装语言包 System Settings–>Language Support–>Install/Remove Languages 选中chinese,点击Apply应用即可,等待下 ...

  10. Python教程(2.7)——条件分支

    像其它语言一样,Python也有条件分支. 例如,输入用户年龄,可能需要判断是否成年,并做出不同反应.这就需要用到条件分支. if条件分支 if条件分支的一般格式如下: if condition: s ...