您的位置:首页 > 理论基础 > 数据结构算法

数据结构,算法与应用(3)

2015-09-14 16:40 246 查看
第8章 二叉树和其他树

1. 术语:

树和二叉树的术语,如高度、深度、层、根、叶子、子节点、父节点和兄弟节点。

4种常用的二叉树遍历方法:前序遍历,中序遍历,后序遍历和按层遍历。

2. 线性数据结构,表数据结构,层次数据结构

3. 二叉树与树的根本区别

4. 二叉树的特性

5. 二叉树遍历方法

在前三种方法中,每个节点的左子树在其右子树之前遍历。这三种遍历的区别在于对同一个节点在不同时刻进行访问。在进行前序遍历时,每个节点是在其左右子树被访问之前进行访问的;在中序遍历时,首先访问左子树,然后访问子树的根节点,最后访问右子树。在后序遍历时,当左右子树均访问完之后才访问子树的根节点。

在逐层遍历过程中,按从顶层到底层的次序访问树中元素,在同一层中,从左到右进行访问。由于遍历中所使用的数据结构是一个队列而不是栈,因此写一个按层遍历的递归程序很困难。

6. 二叉树遍历一个常用问题:数学表达式的形式

当对一棵数学表达式树进行中序,前序和后序遍历时,就分别得到表达式的中缀、前缀和后缀形式。中缀( infix)形式即平时所书写的数学表达式形式,在这种形式中,每个二元操作符(也就是有两个操作数的操作符)出现在左操作数之后,右操作数之前。在使用中缀形式时,可能会产生一些歧义。例如, x+y×z 可以理解为 (x+y)×z 或x+(y×z)。为了避免这种歧义,可

对操作符赋于优先级并采用优先级规则来分析中缀表达式。在完全括号化的中缀表达式中,每个操作符和相应的操作数都用一对括号括起来。更甚者把操作符的每个操作数也都用一对括号括起来。如 ((x)+(y)),((x)+((y)*(z)))和(((x)+(y))*((y)+(z)))*(w)。

在后缀(postfix)表达式中,每个操作符跟在操作数之后,操作数按从左到右的顺序出现。在前缀( p r e f i x)表达式中,操作符位于操作数之前。在前缀和后缀表达式中不会存在歧义。因此,在前缀和后缀表达式中都不必采用括号或优先级。从左到右或从右到左扫描表达式并采用操作数栈,可以很容易确定操作数和操作符的关系。若在扫描中遇到一个操作数,把它压入堆栈,若遇到一个操作符,则将其与栈顶的操作数相匹配。把这些操作数推出栈,由操作符执行相应的计算,并将所得结果作为操作数压入堆栈。

7. 抽象数据结构:二叉树

二叉树节点代码:



#ifndef _BINARYTREENODE_H_

#define _BINARYTREENODE_H_

template <class T>

class BinaryTree;

class Booster;

template <class T>

class BinaryTreeNode{

friend class BinaryTree<T>;

friend class Booster;

friend void PlaceBoosters(BinaryTreeNode<Booster>*);

public:

BinaryTreeNode(){

lchild=rchild=0;

}

BinaryTreeNode(const T& e){

data=e;

lchild=rchild=0;

}

BinaryTreeNode(const T& e,BinaryTreeNode<T>* l,BinaryTreeNode<T>* r){

data=e;

lchild=l;

rchild=r;

}

T getData(){

return data;

}

BinaryTreeNode<T>* getLChild(){

return lchild;

}

BinaryTreeNode<T>* getRChild(){

return rchild;

}

void setData(const T& e){

data=e;

}

void setLChild(BinaryTreeNode<T>* l){

lchild=l;

}

void setRChild(BinaryTreeNode<T>* r){

rchild=r;

}

private:

T data;

BinaryTreeNode<T> *lchild;

BinaryTreeNode<T> *rchild;

};

#endif

数据类型二叉树类:



#ifndef _BINARYTREE_H_

#define _BINARYTREE_H_

#include <iostream>

#include <queue>

#include "BinaryTreeNode.h"

int _count;

template <class T>

class BinaryTree{

public:

BinaryTree():root(0){}

~BinaryTree(){}

bool IsEmpty()const{

return root?false:true;

}

bool Root(T& x)const;

void MakeTree(const T& elem,BinaryTree<T>& left,BinaryTree<T>& right);

void BreakTree(T& elem,BinaryTree<T>& left,BinaryTree<T>& right);

void PreOrder(void(*Visit)(BinaryTreeNode<T>* u)){

PreOrder(Visit,root);

}

void InOrder(void(*Visit)(BinaryTreeNode<T>* u)){

InOrder(Visit,root);

}

void PostOrder(void(*Visit)(BinaryTreeNode<T>* u)){

PostOrder(Visit,root);

}

void LevelOrder(void(*Visit)(BinaryTreeNode<T>*u));

void PreOutput(){

PreOrder(Output,root);

std::cout<<std::endl;

}

void InOutput(){

InOrder(Output,root);

std::cout<<std::endl;

}

void PostOutput(){

PostOrder(Output,root);

std::cout<<std::endl;

}

void LevelOutput(){

LevelOrder(Output);

std::cout<<std::endl;

}

void Delete(){

PostOrder(Free,root);

root=0;

}

int Height()const{

return Height(root);

}

int Size(){

_count=0;

PreOrder(Add1,root);

return _count;

}

private:

BinaryTreeNode<T> *root;

void PreOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t);

void InOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t);

void PostOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t);

static void Output(BinaryTreeNode<T>* t){

std::cout<<t->data<<' ';

}

static void Free(BinaryTreeNode<T>* t){

delete t;

}

int Height(BinaryTreeNode<T> *t)const;

static void Add1(BinaryTreeNode<T>* t){

_count++;

}

};

template <class T>

bool BinaryTree<T>::Root(T& x)const

{

if(root){

x=root->data;

return true;

}

else

return false;

}

template <class T>

void BinaryTree<T>::MakeTree(const T& elem,BinaryTree<T>& left,BinaryTree<T>& right)

{

root=new BinaryTreeNode<T>(elem,left.root,right.root);

left.root=right.root=0;

}

template <class T>

void BinaryTree<T>::BreakTree(T& elem,BinaryTree<T>& left,BinaryTree<T>& right)

{

if(!root)

throw "BadInput";

elem=root->data;

left.root=root->lchild;

right.root=root->rchild;

delete root;

root=0;

}

template <class T>

void BinaryTree<T>::PreOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t)

{

if(t){

Visit(t);

PreOrder(Visit,t->lchild);

PreOrder(Visit,t->rchild);

}

}

template <class T>

void BinaryTree<T>::InOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t)

{

if(t){

InOrder(Visit,t->lchild);

Visit(t);

InOrder(Visit,t->rchild);

}

}

template <class T>

void BinaryTree<T>::PostOrder(void(*Visit)(BinaryTreeNode<T>*u),BinaryTreeNode<T>* t)

{

if(t){

PostOrder(Visit,t->lchild);

PostOrder(Visit,t->rchild);

Visit(t);

}

}

template <class T>

void BinaryTree<T>::LevelOrder(void(*Visit)(BinaryTreeNode<T>*u )){

std::queue<BinaryTreeNode<T>*> qu;

BinaryTreeNode<T>* t;

qu.push(root);

while(!qu.empty()){

t=qu.front();

if(t){

Visit(t);

if(t->lchild)

qu.push(t->lchild);

if(t->rchild)

qu.push(t->rchild);

}

qu.pop();

}

}

template <class T>

int BinaryTree<T>::Height(BinaryTreeNode<T> *t)const{

if(!t)

return 0;

int hl=Height(t->lchild);

int hr=Height(t->rchild);

if(hl>hr)

return ++hl;

else

return ++hr;

}

#endif

二叉树测试代码:



#include <iostream>

#include "BinaryTree.h"

using namespace std;

int count=0;

BinaryTree<int> a,x,y,z;

template<class T>

void ct(BinaryTreeNode<T> *t){

count++;

}

void test1(){

y.MakeTree(10,a,a);

z.MakeTree(20,a,a);

x.MakeTree(30,y,z);

y.MakeTree(40,x,a);

y.PreOrder(ct);

cout<<count<<endl;

y.PreOutput();

y.InOutput();

y.PostOutput();

y.LevelOutput();

}

void test2(){

y.MakeTree(1,a,a);

z.MakeTree(2,a,a);

x.MakeTree(3,y,z);

y.MakeTree(4,x,a);

cout << "Preorder sequence is ";

y.PreOutput();

cout << "Inorder sequence is ";

y.InOutput();

cout << "Postorder sequence is ";

y.PostOutput();

cout << "Level order sequence is ";

y.LevelOutput();

cout << "Number of nodes = ";

cout << y.Size() << endl;

cout << "Height = ";

cout << y.Height() << endl;

y.PreOrder(ct);

cout << "Count of nodes is " << count << endl;

}

int main(){

test2();

}

8. 删除二叉树

要删除一棵二叉树,需要删除其所有节点。可以通过后序遍历在访问一个节点时,把其删除。也就是说先删除左子树,然后右子树,最后删除根。

9. 计算高度

通过进行后序遍历,可以得到二叉树的高度。首先得到左子树的高度 hl,然后得到右子树的高度hr。此时,树的高度为:

max{hl,hr} + 1

10.设置信号放大器

代码如下:



#include <iostream>

#include "BinaryTree.h"

using namespace std;

int tolerance = 3;

class Booster{

friend int main();

friend void PlaceBoosters(BinaryTreeNode<Booster>*);

public:

void Output(ostream& out)const{

out<<boost<<' '<<D<<' '<<d<<' ';

}

private:

int D,d;

bool boost;

};

ostream& operator<<(ostream& out,const Booster& x)

{

x.Output(out);

return out;

}

void PlaceBoosters(BinaryTreeNode<Booster>* x){

BinaryTreeNode<Booster> *y=x->getLChild();

int degr;

Booster btr;

btr.D=0;

x->data.D=0;

if(y){

degr=(y->getData()).D+(y->getData()).d;

if(degr>tolerance){

y->data.boost=true;

x->data.D=y->data.d;

}

else

x->data.D=degr;

}

y=x->getRChild();

if(y){

degr=y->data.D+y->data.d;

if(degr>tolerance) {

y->data.boost=true;

degr=y->data.d;

}

if(x->data.D<degr)

x->data.D=degr;

}

}

BinaryTree<Booster> T, U, V, W, X, Y;

int main(void)

{

Booster a, b;

a.d = 2; a.D =0; a.boost = 0;

b.d=1; b.D=0; b.boost = 0;

U.MakeTree(a,X,X);

V.MakeTree(b,U,X);

U.MakeTree(a,X,X);

W.MakeTree(a,U,X);

b.d=3;

U.MakeTree(b,V,W);

V.MakeTree(a,X,X);

b.d=3;

W.MakeTree(b,X,X);

Y.MakeTree(a,V,W);

W.MakeTree(a,X,X);

T.MakeTree(b,Y,W);

b.d=0;

V.MakeTree(b,T,U);

V.PostOrder(PlaceBoosters);

V.PostOutput();

}

11. 树与二叉树(详细介绍)

12. 在线等价类问题

(1)利用数组解决

代码如下:



//Online equivalence class functions using arrays

#include <iostream>

using namespace std;

int *E, n;

void Initialize(int n)

{// Initialize n classes with one element each.

E = new int [n + 1];

for (int e = 1; e <= n; e++)

E[e] = e;

}

void Union(int i, int j)

{// Union the classes i and j.

for (int k = 1; k <= n; k++)

if (E[k] == j) E[k] = i;

}

int Find(int e)

{// Find the class that contains element i.

return E[e];

}

int main(void)

{

n = 10;

Initialize(n);

Union(1,2);

Union(3,4);

Union(1,3);

cout << '1' << ' ' << Find(1) << ' ' << '2' << ' ' << Find(2) << endl;

cout << '3' << ' ' << Find(3) << ' ' << '4' << ' ' << Find(4) << endl;

cout << '5' << ' ' << Find(5) << ' ' << '6' << ' ' << Find(6) << endl;

}

(2)利用树解决

代码如下:



//Simple tree solution to union-find problem

//

#include <iostream>

using namespace std;

int *parent;

void Initialize(int n){

parent=new int[n+1];

for(int e=1;e<=n;e++)

parent[e]=0;

}

int Find(int e){

while(parent[e])

e=parent[e];

return e;

}

void Union(int i,int j){

parent[j]=i;

}

int main(void)

{

Initialize(10);

Union(1,2);

Union(3,4);

Union(1,3);

cout << "Find(1) = " << Find(1) << " Find(2) = " << Find(2) << endl;

cout << "Find(3) = " << Find(3) << " Find(4) = " << Find(4) << endl;

cout << "Find(5) = " << Find(5) << " Find(6) = " << Find(6) << endl;

}

(3)利用重量或高度规则来提高性能
代码如下:



// union/find with weighting rule

#include <iostream>

#include <cstdlib>

using namespace std;

int *parent;

bool *root;

void Initialize(int n)

{// One element per set/class/tree.

root = new bool[n+1];

parent = new int[n+1];

for (int e = 1; e <= n; e++) {

parent[e] = 1;

root[e] = true;}

}

int Find(int e)

{// Return root of tree containing e.

while (!root[e])

e = parent[e]; // move up one level

return e;

}

int Find_compact(int e)

{// Return root of tree containing e.

// Compact path from e to root.

int j = e;

// find root

while (!root[j])

j = parent[j];

// compact

int f = e; // start at e

while (f != j) {// f is not root

int pf = parent[f];

parent[f] = j; // move f to level 2

f = pf; // f moves to old parent

}

return j;

}

void Union(int i, int j)

{// Combine trees with roots i and j.

// Use weighting rule.

if (parent[i] < parent[j]) {

// i becomes subtree of j

parent[j] += parent[i];

root[i] = false;

parent[i] = j; }

else {// j becomes subtree of i

parent[i] += parent[j];

root[j] = false;

parent[j] = i;}

}

int main(void)

{

Initialize(10);

Union(1,2);

Union(3,4);

Union(1,3);

cout << '1' << ' ' << Find(1) << ' ' << '2' << ' ' << Find(2) << endl;

cout << '3' << ' ' << Find(3) << ' ' << '4' << ' ' << Find(4) << endl;

cout << '5' << ' ' << Find(5) << ' ' << '6' << ' ' << Find(6) << endl;

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: