封装排序二叉树&随机数生成(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‘;
}
}