二叉树和排序

 
二叉树和排序
排序是算法中最典型的一类问题,也是显示计算机的特点的一类问题。在任何计算机算法课程中,都会先后给出几种著名的排序算法。二叉树排序是众多排序算法中很有趣的一个,随着排序二叉树的生成过程,整个排序任务也得到了完成。 
下图是两个简单的排序二叉树例子:
序列:3, 8, 1
排序二叉树:
3
//
/  /
1   8
 -------->
然后,按照上图中箭头的方向,从左到右依次读出树中的数字,就是排序的结果:1, 3, 8。
序列:7, 14, 9, 11, 5, 17
排序二叉树:
7
//
/  /
5       14
        //
        /  /
         9     17
  /
    /
  11
------------->
同样,按照上图箭头的方向,从左到右依次读数的结果为:5, 7, 9, 11, 14, 17。 
观察这些例子,可以验证排序二叉树的定义。排序二叉树的任何一个节点是:
  • 空节点或者,
  • 左子节点,数值,右子节点的组合,
    • 其中左子节点,右子节点分别是一个排序二叉树;
    • 所有左子节点二叉树中的数值<本节点的数值<所有右子节点二叉树中的数值。
根据这个定义,首先可以确定的是二叉树的数据结构,其实现如下: 
template<class T, int n, class U> struct Tree{
     typedef T Left;
     static const int value = n;
     typedef U Right;
}; 
整个排序过程,就是建立二叉树的过程,因此可以大致写出这个算法的思路:
  • 首先是简单情况平凡解,如果待排序序列为空,则返回一个空二叉树。
  • 普通情况下:
    • 从序列中取出第1个元素;
    • 然后将序列中剩余的元素建立成一排序二叉树;
    • 最后,将第1个元素插入到此二叉树中。
这个算法叙述非常简单,但是其引入了一个新的关键问题——“插入”。在解决“插入”这个关键问题前,算法可实现如下: 
//算法定义
template<class NList> struct BuildSortTree;
//平凡解
template<> struct BuildSortTree<Empty>{
     typedef Empty Result;
};
//普通情况
template<class NList> struct BuildSortTree{
     typedef typename InsertToTree<
          NList::First,
          typename BuildSortTree<typename NList::Rest>::Result
     >::Result Result;
};
红色粗体表示引入的新“关键问题”,也就是将一个数值插入到某排序二叉树的算法。根据排序二叉树定义中的最后一点,可以描述如下:
  • 简单情况平凡解:若待插入二叉树为空,则返回形式为{空,数值,空}的二叉树;
  • 在普通情况下:
    • 若待插入元素小于根节点数值,则将其插入到左子树中;
    • 反之,将此元素插入到右子树中。
根据这个叙述,此插入算法可以实现如下:
//定义
template<int n, class NTree> struct InsertToTree;
//平凡解
template<int n> struct InsertToTree<n, Empty>{
     typedef Tree<Empty, n, Empty> Result;
};
//普通情况
template<int n, class NTree> struct InsertToTree{
     template<bool x> struct If;
     template<> struct If<true>{
          typedef Tree<
              typename InsertToTree<n, typename NTree::Left>::Result,
              NTree::value,
              typename NTree::Right> Result;
     };
     template<> struct If<false>{
          typedef Tree<
              typename NTree::Left,
              NTree::value,
              typename InsertToTree<n, typename NTree::Right>::Result
              > Result;
     }; 
     typedef typename If< (n<NTree::value) >::Result Result;
}; 
为了验证算法的正确性,还需要一个能够打印出二叉树的程序,该程序从左到右依次扫描整棵树,凡节点为空则跳过,否则打印出节点的数值。其实现如下:
template<class NTree> struct PrintTree{
     static void print(){
          PrintTree<typename NTree::Left>::print();
          std::cout<<NTree::value<<", ";
          PrintTree<typename NTree::Right>::print();
     }
}; 
template<> struct PrintTree<Empty>{
     static void print(){}
}; 
写在main()函数中的测试代码为: 
typedef List<7, List<14, List<9,
List<11, List<5, List<17, Empty>>>>>> TestList;
PrintTree< BuildSortTree<TestList>::Result >::print(); 
程序输出排好的序列:5, 7, 9, 11, 14, 17。
Scheme 代码参考 
排序二叉树代码
(define-struct num-tree (left n right)) 
(define (insert-to-tree n atree)
  (cond
    [(empty? atree) (make-num-tree empty n empty)]
    [(< n (num-tree-n atree))
      (make-num-tree
        (insert-to-tree n (num-tree-left atree))
        (num-tree-n atree)
        (num-tree-right atree) )]
    [else
      (make-num-tree
        (num-tree-left atree)
        (num-tree-n atree)
        (insert-to-tree n (num-tree-right atree)) )]wink
(define (BST alon)
  (cond
    [(empty? alon) empty]
    [else (insert-to-tree (first alon) (BST (rest alon)) )]wink)  

 
 
 



网 易 Yeah.net 邮 箱 夏 日 大 变 脸,带 你 感 受 新 一 代 邮 箱 的 全 新 魅 力 >>   
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值