[C++]封装排序二叉树&随机数生成(c++11)

封装排序二叉树&随机数生成(c++11)

本文,我尝试着把排序二叉树封装为一个模板类,并且用C++11给出的随机数生成函数来对这个类进行测试。

排序二叉树封装

这个二叉树的特征是,左子数的值肯定比父节点小,右子树的值肯定比父节点的大。要求大家按照这个结构特征去构建二叉树,最后中序遍历输出就是我们要求的升序输出。

我们可以根据具体的要求来完成对排序二叉树的构建,可以用一个bool函数来区别不同排序顺序,默认是升序。紧接着用递归来不断地insert新的节点。最后用中序遍历就可以得到我们需要的排序结果。如果想要改变visit输出方式,要也可以设定一个函数指针。不过因为封装性,还需要在类里面增加对Node的内部访问。

//
//  main.cpp
//  排序
//
//  Created by 颜泽鑫 on 5/9/16.
//  Copyright ? 2016 颜泽鑫. All rights reserved.
//

#include <iostream>
#include <vector>
#include <random>
#include <time.h>
#include <algorithm>
#include <iomanip>
using namespace std;
template <typename T>
bool cmps(T a, T b);
template <typename T>
class BinaryTree {
public:
    struct Node {
        T value;
        Node* left;
        Node* right;
        Node(T vals = 0, Node* lefts = NULL, Node* rights = NULL) : value(vals), left(lefts), right(rights) {
        }
    };
    BinaryTree(const std::vector<T>& orig, bool (*cmp)(T a, T b) = cmps<T>);
    ~BinaryTree();
    void print();
private:
    Node* root;
    void insert(Node* root, T value, bool (*cmp)(T a, T b));
    void clear(Node* temp);
    void visit(Node* root);
};
template <typename T>
bool cmps(T a, T b) {
    if (a <= b) {
        return true;
    } else {
        return false;
    }
}

template <typename T>
void BinaryTree<T>::insert(BinaryTree::Node *root, T value, bool (*cmp)(T a, T b)) {
    if (cmp(value, root->value)) {
        if (root->left == NULL) {
            Node* temp = new Node(value);
            root->left = temp;
        } else {
            insert(root->left, value, cmp);
        }
    } else {
        if (root->right == NULL) {
            Node* temp = new Node(value);
            root->right = temp;
        } else {
            insert(root->right, value, cmp);
        }
    }
}

template <typename T>
BinaryTree<T>::BinaryTree(const std::vector<T>& orig, bool (*cmp)(T a, T b)) {
    root = new Node(orig[0]);
    for (int i = 1; i != orig.size(); i++) {
        insert(root, orig[i], cmp);
    }
}
template <typename T>
void BinaryTree<T>::clear(Node* root) {
    if (root != NULL) {
        clear(root->left);
        clear(root->right);
        delete root;
    }
}
template <typename T>
BinaryTree<T>::~BinaryTree() {
    clear(root);
}
template <typename T>
void BinaryTree<T>::visit(BinaryTree::Node *root) {
    if (root != NULL) {
        visit(root->left);
        std::cout << root->value << " ";
        visit(root->right);
    }
}
template <typename T>
void BinaryTree<T>::print() {
    visit(root);
}

测试函数:

int main() {
    int range;
    std::cin >> range;
    int total_num = range;
    std::vector<double> input;
    std::random_device ram;
    std::uniform_real_distribution<> dis(1, range);
    double value = 0;
    while (total_num--) {
        value = dis(ram);
        input.push_back(value);
    }
    BinaryTree<double> tree(input);
    tree.print();
    return 0;
}

随机数生成类

接下来我们讨论随机数的生成方法。

在C++11中给出了一个新的特性来完成随机数的生成。

1. random_device

标准库提供了一个非确定性随机数生成设备.在Linux的实现中,是读取/dev/urandom设备;Windows的实现居然是用rand_s,在这里强烈谴责一下.

random_device提供()操作符,用来返回一个min()到max()之间的一个数字.如果是Linux(Unix Like或者Unix)下,都可以使用这个来产生高质量的随机数,可以理解为真随机数.

#include <iostream>
#include <random>
int main() {
  std::random_device rd;
  for(int n=0; n<20000; ++n)
    std::cout << rd() << std::endl;
  return 0;
}

2. random number engine

标准把随机数抽象成随机数引擎分布两部分.引擎用来产生随机数,分布产生特定分布的随机数(比如平均分布,正太分布等).

标准提供三种常用的引

擎:linear_congruential_engine,mersenne_twister_engine和subtract_with_carry_engine.第一种是线性同余算法,第二种是梅森旋转算法,第三种带进位的线性同余算法.第一种是最常用的,而且速度也是非常快的; 第二种号称是最好的伪随机数生成器;第三种没用过….

随机数引擎接受一个整形参数当作种子,不提供的话,会使用默认值. 推荐使用random_device来产生一个随机数当作种子.(windows下爱咋整咋整,谁叫windows的random_device是调用rand_s)

#include <iostream>
#include <random>

int main()
{
  std::random_device rd;
  std::mt19937 mt(rd());
  for(int n = 0; n < 10; n++)
    std::cout << mt() << std::endl;
  return 0;
}

3. random number distributions

标准提供各种各样的分布,不过我们经常用的比较少,比如平均分布,正太分布…使用也很简单

//平均分布
#include <random>
#include <iostream>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 6);
    for(int n=0; n<10; ++n)
        std::cout << dis(gen) << ‘ ‘;
    std::cout << ‘\n‘;
}
//正态分布
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
int main() {
    std::random_device rd;
    std::mt19937 gen(rd());

    // values near the mean are the most likely
    // standard deviation affects the dispersion of generated values from the mean
    std::normal_distribution<> d(5,2);

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[std::round(d(gen))];
    }
    for(auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ‘ ‘ << std::string(p.second/200, ‘*‘) << ‘\n‘;
    }
}
时间: 2024-08-02 11:26:23

[C++]封装排序二叉树&随机数生成(c++11)的相关文章

C++11 智能指针unique_ptr使用 -- 以排序二叉树为例

用智能指针可以简化内存管理.以树为例,如果用普通指针,通常是在插入新节点时用new,在析构函数中调用delete:但有了unique_ptr类型的智能指针,就不需要在析构函数中delete了,因为当unique_ptr类型的指针P生命结束时(比如对于局部变量,程序执行到局部变量的作用域范围之外),P会自动delete它拥有的资源(指针指向的空间).对于shared_ptr,情况更加复杂一些,shared_ptr会维护一个use count,即有多少个指针共享这一资源,当use count为0时,

排序二叉树

题目大意:请完成下面四个函数的定义(在tree.h文件中),使整个程序能够利用排序二叉树的结构对输入的数(不会出现相同的数),进行排序输出.节点的结构体在下面已给出,这个二叉树的特征是,左子数的值肯定比父节点小,右子树的值肯定比父节点的大.要求大家按照这个结构特征去构建二叉树,最后中序遍历输出就是我们要求的升序输出. 树的节点结构体为: typedef struct Node { struct Node *left; struct Node *right; int value; } Node;

纪念逝去的岁月——C/C++排序二叉树

1.代码 2.运行结果 3.分析 1.代码 #include <stdio.h> #include <stdlib.h> typedef struct _Node { int value; struct _Node * pLeft; struct _Node * pRight; } Node; Node * getNewNode(int iValue) { Node * p = (Node *)malloc(sizeof(Node)); if(NULL != p) { p->

数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n(≥0)结点组成的有限集合.{N.沃恩}     (树是n(n≥1)个结点组成的有限集合.{D.E.Knuth})      在任意一棵非空树中:        ⑴有且仅有一个没有前驱的结点----根(root).        ⑵当n>1时,其余结点有且仅有一个直接前驱.         ⑶所有结

(eden)排序二叉树VS二叉树链表

排序二叉树 Description: If you have any doubt on this assignment, please send an email to its author 黎洋. --> 题目大意:请完成下面四个函数的定义(在tree.h文件中),使整个程序能够利用排序二叉树的结构对输入的数(不会出现相同的数),进行排序输出.节点的结构体在下面已给出,这个二叉树的特征是,左子数的值肯定比父节点小,右子树的值肯定比父节点的大.要求大家按照这个结构特征去构建二叉树,最后中序遍历输

一步一步写算法(之排序二叉树删除-1)

原文:一步一步写算法(之排序二叉树删除-1) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 相比较节点的添加,平衡二叉树的删除要复杂一些.因为在删除的过程中,你要考虑到不同的情况,针对每一种不同的情况,你要有针对性的反应和调整.所以在代码编写的过程中,我们可以一边写代码,一边写测试用例.编写测试用例不光可以验证我们编写的代码是否正确,还能不断提高我们开发代码的自信心.这样,即使我们在开发过程对代码进行修改或者优化也不会担心害怕.然而看起

判断排序二叉树的后序遍历是否正确(对递归算的总结)

是 #include <iostream> using namespace std; //排序二叉树的性质 /* *.终止条件:1.开始>=结尾返回真 *. 2.s >= e 因为不出现问题的话,一定能到达 s>=e的情况.知道到达了s >= e即为真 *. 1.最后一个节点是root 2.在root之前的节点 连续的大于root的是其右子树, 再之前连续小于root的是其左子树 3.递归调用 */ bool treehelper(int a[], int s, int

2241 排序二叉树

2241 排序二叉树 2001年CTSC国家队选拔赛 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题解 题目描述 Description 一个边长为n的正三角形可以被划分成若干个小的边长为1的正三角形,称为单位三角形.边长为3的正三角形被分成三层共9个小的正三角形,我们把它们从顶到底,从左到右以1~9编号.同理,边长为n的正三角形可以划分成n2个单位三角形. 四个这样的边长为n的正三角形可以组成一个三棱锥.我们将正三棱锥的三个侧面依顺时针次序(从顶向底视角

一步一图一代码之排序二叉树

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong/) 属性: ①若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值. ②若它的右子树不为空,则右子树上所有节点的值均大于它的根节点的值. ③它的左.右子树也都是排序二叉树. 添加操作: 当根节点为空时,添加进的节点作为根节点.然后每次添加节点时,都从根节点过滤,以根节点作为当前节点,如果新节点大于当前节点,则走当前节点的右子节点分支,如果新节点小于当前节点,则走当前节点的左子节点分支.然后再用右子节点