第5章二叉树
|
|
|
- 龟议开 堵
- 9 years ago
- Views:
Transcription
1 第 5 章二叉树 5.1 二叉树的概念 5.2 二叉树的周游 5.3 二叉树的存储结构 5.4 二叉搜索树 5.5 堆 5.6 Huffman 编码树 5.1 二叉树的概念 二叉树的定义及相关概念 满二叉树 完全二叉树 扩充二叉树 二叉树的主要性质 二叉树的定义和基本术语 二叉树的五种基本形态 二叉树由结点的有限集合构成 这个有限集合 或者为空集 ; 或者由一个根结点及两棵互不相 交的分别称为左子树 右子树的二叉树组成 这是一个递归定义 二叉树可以是空集合, 因 空二叉树 左右为空 左非空 右非空 左右都不空 此根可以有空的左子树或右子树, 或者左右子 树皆为空 满二叉树 完全二叉树 扩充二叉树 如果一棵二叉树的任何结点, 或者是树叶, 或者恰有两棵非空子树, 则此二叉树称作满二叉树 完全二叉树如果一棵二叉树最多只有最下面的两层结点度数可以小于 2; 最下面一层的结点都集中在该层最左边的位置上, 则称此二叉树为完全二叉树 5 6 1
2 扩充二叉树 扩充二叉树 当二叉树里出现空的子树时, 就增加新的 特殊的结点 空树叶 对于原来二叉树里度数为 1 的分支结点, 在它下面增加一个空树叶 对于原来二叉树的树叶, 在它下面增加两个空树叶扩充的二叉树是满二叉树, 新增加的空树叶 ( 外部结点 ) 的个数等于原来二叉树的结点 ( 内部结点 ) 个数加 扩充二叉树 外部路径长度 E 从扩充的二叉树的根到每个外部结点的路径长度之和 内部路径长度 I 扩充的二叉树里从根到每个内部结点的路径长度之和 E 和 I 两个量之间的关系为 E=I+2n 二叉树的主要性质 1. 满二叉树定理 : 非空满二叉树的树叶结点数量等于其分支结点数量加 1 证明 : 设二叉树结点总数为 n, 叶结点数为 m, 分支结点数为 b n = m + b ( 公式 1) 每个分支结点恰有两个子结点, 故有 2*b 条边 ; 一棵二叉树, 除根结点外, 每个结点都恰有一条边联接父结点, 故共有 n-1 条边 即 n - 1 = 2b ( 公式 2) 由 ( 公式 1),( 公式 2) 得 n-1=m+b-1 = 2b, 得出 m = b 满二叉树定理推论 : 一个非空二叉树的空子树 ( 指针 ) 数目等于其结点数加 1 证明 : 设二叉树 T, 将其所有空子树换为树叶, 记 新的扩充满二叉树为 T 所有原来 T 的结点现在是 T 的分支结点 根据满二叉树定理, 新添加的树 叶数目等于 T 结点个数加 1, 而每个新添加的树叶 对应 T 的一个空子树 因此 T 中空子树数目等于 T 中结点数加 1 3. 任何一棵二叉树, 度为 0 的结点比度为 2 的结点多一个 n 0 = n 证明 : 设有 n 个结点的二叉树度为 的结点数分别为 =n 0,n 1,n 2, 则 n = n 0 + n 1 + n 2 ( 公式 3) 设边数为 e 因为除根以外, 每个结点都有一条边进入, 故 n = e + 1 由于这些边是有度为 1 和 2 的的结点射出的, 因此 e = n n 2, 于是 n = e + 1= n n ( 公式 4) 因此由 ( 公式 3)( 公式 4) 得 n 0 + n 1 + n 2 = n n 即 n 0 = n
3 4. 二叉树的第 i 层 ( 根为第 0 层,i 0) 最多有 2 i 个结点 证明 :( 数学归纳法 ) i=0, 只有根结点, 2 0 =1 成立假设 0 j<i,2 j 成立, 当 j+1,2 j *2=2 j+1 则第 j 层至多有 2 j+1 二叉树的高度定义为二叉树中层数最大的叶结点的层数加 1 二叉树的深度定义为二叉树中层数最大的叶结点的层数 深度为 k 的二叉树至多有 2 k+1-1 个结点 证明 : 利用性质 k =2 k 有 n 个结点 (n>0) 的完全二叉树的高度为 log 2 (n+1), 深度为 log 2 (n+1) -1 证明 : 设高度为 k, 则有 : 2 k-1-1<n<=2 k -1 2 k-1 <=n<2 k k-1<=log 2 n<k 因为 k 是整数, 所以 k= log 2 (n+1) 对于具有 n 个结点的完全二叉树, 结点按层次由左到右编号, 则有 : (1) 如果 i=0 为根结点 ; 如果 i>0, 其父结点编号是 (i-1)/2. (2) 当 2i+1<n, 结点的左子结点是 2i+1; 否则没有左子结点 (3) 当 2i+2<n, 结点的右子结点是 2i+2; 否则 i 没有右子结点 5.2 二叉树的周游 二叉树的抽象数据类型 深度周游二叉树 广度周游二叉树
4 5.2.1 二叉树的抽象数据类型 T value() const; 二叉树结点 二叉树的操作 : 整棵二叉树的运算 初始化二叉树 合并两棵二叉树 二叉树的结点运算 访问结点的左 / 右子结点 父结点 访问结点存储的数据 class BinaryTreeNode { friend class BinaryTree<T>; private: T info; BinaryTreeNode *leftchild,*rightchild; public: BinaryTreeNode(); BinaryTreeNode(const T& ele); BinaryTreeNode(const T& ele, BinaryTreeNode<T>* l, BinaryTreeNode<T>* leftchild() const; BinaryTreeNode<T>* rightchild() const; void setleftchild(bianrytreenode<t>*); void setrightchild(binarytreenode<t>*); void setvalue(const T& val); bool isleft() const; BinaryTreeNode<T>& operator= (const BianryTreeNode<T>& Node); BinaryTreeNode<T> *r); class BinaryTree { 二叉树 private: BinaryTreeNode<T> * root; public: BinaryTree(){ root = NUL; ~BinaryTree() { DeleteBinaryTree(root); bool isempty() const; BinaryTreeNode<T>* Root(){ return root; BinaryTreeNode<T>* Parent(BinaryTreeNode<T>* current); BinaryTreeNode<T>* LeftSibling(BinaryTreeNode<T>* current); BinaryTreeNode<T>* RightSibling(BinaryTreeNode<T>* current); void CreateTree(const T& info, BinaryTree<T>& lefttree, BinaryTree<T>& righttree); void PreOrder(BinaryTreeNode<T>* root); void InOrder(BinaryTreeNode<T>* root); void PostOrder(BinaryTreeNode<T>* root); void LevelOrder(BinaryTreeNode<T>* root); void DeleteBinaryTree(BinaryTreeNode<T>* root); 深度优先周游二叉树 所谓周游是指系统地访问数据结构中的每个结点一次且仅一次 周游一棵二叉树的过程就是将二叉树的结点放入一个线性序列的过程, 即将二叉树线性化 22 深度优先周游二叉树 可以有下列三种周游顺序 : 1 前序周游 (tlr 次序 ): 访问根结点 ; 前序周游左子树 ; 前序周游右子树 2 中序周游 (LtR 次序 ): 中序周游左子树 ; 访问根结点 ; 中序周游右子树 3 后序周游 (LRt 次序 ): 后序周游左子树 ; 后序周游右子树 ; 访问根结点 深度优先周游二叉树 1 前序周游 : ABDCEGFHI 2 中序周游 : DBAEGCHFI 3 后序周游 : DBGEHIFCA
5 前序周游二叉树 ( 递归实现 ) void BinaryTree<T>::PreOrder( BinaryTreeNode<T>* root ){ if ( root!= NULL) { Visit(root->value()); // 访问根结点 PreOrder(root->leftchild()); // 前序周游左子树 PreOrder(root->rightchild()); // 前序周游右子树 中序周游二叉树 ( 递归实现 ) void BinaryTree<T>::InOrder(BinaryTreeNode<T>* root) { if ( root!= NULL) { InOrder(root->leftchild()); // 中序周游左子树 Visit(root->value()); // 访问根结点 InOrder(root->rightchild()); // 中序周游右子树 后序周游二叉树 ( 递归实现 ) void BinaryTree<T>::PostOrder(BinaryTreeNode<T>* root) { if( root!= NULL) { PostOrder(root->leftchild()); // 后序周游左子树 PostOrder(root->rightchild()); // 后序周游右子树 Visit(root->value()); // 访问根结点 非递归深度优先周游二叉树将递归转换为非递归需要借用栈模拟执行递归的过程 即利用一个栈记录尚未周游的结点或子树, 以备以后访问 前序周游二叉树算法 ( 非递归 ) pointer = root; a 空指针入栈 ; while ( pointer 非空 ){ b Visit(pointer); if (pointer 有右结点 ) 右结点入栈 ; c d if (pointer 有左结点 ) 左结点入栈 ; e 退栈 ; g f h 前序周游二叉树 ( 非递归 ) void BinaryTree<T>::PreOrderWithoutRecursion(BinaryTreeNode<T>* root) { using std::stack; stack<binarytreenode<t>*> astack; BinaryTreeNode<T> * pointer = root; astack.push(null); while (pointer) { Visit(pointer->value()); if (pointer->rightchild()!= NULL) astack.push(pointer->rightchild()); if (pointer->leftchild()!= NULL) astack.push(pointer->leftchild()); pointer=astack.top(); astack.pop();
6 中序周游二叉树算法 ( 非递归 ) pointer = root; while ( 栈非空 pointer 非空 ) { if (pointer 非空 ) { 入栈 ;pointer 指向左结点 ; else { pointer = 退栈 ; Visit(pointer); Pointer 指向右结点 ; c b e d g a f h 中序周游二叉树 ( 非递归 ) void BinaryTree<T>::InOrderWithoutRecursion(BinaryTreeNode<T>* root) { using std::stack; stack<binarytreenode<t>*> astack; BinaryTreeNode<T> * pointer = root; while (!astack.empty() pointer) { if (pointer) { astack.push(pointer); pointer = pointer->leftchild(); else { pointer = astack.top(); astack.pop(); Visit(pointer->value()); pointer = pointer->rightchild(); 后序周游二叉树算法 ( 非递归 ) pointer = root; while ( 栈非空 pointer 非空 ) { while (pointer 非空 ) { 入栈 ;pointer 指向左结点 ; pointer = 退栈 ; if ( 标志为左 ){ 换右标志入栈 ; pointer 指向右结点 ; else { Visit(pointer); pointer = NULL; c b e d g a f h 33 后序周游二叉树 ( 非递归 ) // 栈元素的定义 enum Tags{ Left, Right ; class StackElement { public: BinaryTreeNode<T> * pointer; Tags tag; ; 34 后序周游二叉树 ( 非递归 ) void BinaryTree<T>::PostOrderWithoutRecursion(BinaryTreeNode<T>* root) { using std::stack; StackElement<T> element; stack<binarytreenode<t>> astack; BinaryTreeNode<T> * pointer = root; astack.push(null); while (!astack.empty() pointer) { while ( pointer) { 入栈 ;pointer 指向左结点 ; element = astack.top(); astack.pop(); if (element.tag == Left) { 换右标志入栈 ; pointer 指向右结点 ; else { Visit(pointer->value()); pointer = NULL; element.pointer = pointer; element.tag=left; astack.push(element); pointer=pointer->leftchild(); element.tag=right; astack.push(element); pointer=pointer->rgihtchild(); 广度优先周游二叉树 从二叉树的顶层 ( 根结点 ) 开始, 自上至下逐层遍历 ; 在同一层中, 按照从左到右的顺序对结点逐一访问 例如 :ABCDEFGHI
7 广度优先周游二叉树算法 pointer = root; if (pointer) 入队 ; while ( 队非空 ) { pointer = 出队 ; Visit(pointer); if (pointer 左结点非空 ) 左结点入队 ; if (pointer 右结点非空 ) 右结点入队 ; 37 广度优先周游二叉树 void BinaryTree<T>::LevelOrder(BinaryTreeNode<T>* root) { using::queue; queue<binarytreenode<t> *> aqueue; BinaryTreeNode<T> *pointer=root; if (pointer) aqueue.push(pointer); while (!aquene.empty()) { pointer = aqueue.front(); aqueue.pop(); Visit(pointer->value()); if (pointer->leftchild()) aqueue.push(pointer->leftchild()); if (pointer->rightchild()) aqueue.push(pointer->rightchild()); 二叉树的存储结构 二叉树的链式存储结构 完全二叉树的顺序存储结构 二叉树的链式存储结构 二叉树是非线性的树形结构, 在存储器里表示树形结构的最自然方法是链接方法 在每个结点中除存储结点本身的数据外再设置两个指针字段 llink 和 rlink, 分别指向结点的左子女和右子女 当结点的某个子女为空时, 则相应的指针为空指针 结点的形式为 llink info rlink llink info parent rlink 用链式存储结构表示二叉树 用二叉链表实现二叉树的定义 private: // 二叉树结点的数据域 T info; // 二叉树结点指向左子树的指针 BinaryTreeNode<T>* leftchild; // 二叉树结点指向左子树的指针 BinaryTreeNode<T>* rightchild;
8 BinaryTreeNode<T>* BinaryTree<T>::Parent(BinaryTreeNode<T> *current) { pointer = root; if ( 树非空 && current 非空 ) { a while ( 栈非空 pointer 非空 ) { if (pointer 非空 ) { if (current 是 pointer 的左结点或右结点 ) return pointer; // 找到 current 的父结点 b h 将 pointer 入栈 ; pointer = pointer->leftchild(); // 向左走 c d else { pointer= 出栈 ; e f pointer=pointer->rightchild(); // 向右走 g 返回 current 的父结点 BinaryTreeNode<T>* BinaryTree<T>::Parent(BinaryTreeNode<T> *current) { using std::stack; stack<binarytreenode<t> *> astack; BinaryTreeNode<T> *pointer=root; if (root && current) { while (!astack.empty() pointer) { if (pointer) { if (current == pointer->leftchild() current == pointer->rightchild()) return pointer; astack.push(pointer); pointer=pointer->leftchild(); else { pointer=astack.top(); astack.pop(); pointer=pointer->rightchild(); 返回 current 的父结点 void BinaryTree<T>::CreateTree(const T& info, 创建二叉树 BinaryTree<T>& lefttree, BinaryTree<T>& righttree) { root=new BinaryTreeNode<T>(info,leftTree.root,rightTree.root); lefttree.root = righttree.root = NULL; lefttree 和 righttree 是两棵已有的二叉树 将原子树的根设置为 NULL 是为了避免非法访问子树 删除二叉树 void BinaryTree<T>::DeleteBinaryTree( BinaryTreeNode<T>* root) { if (root!= NULL) { // 当树不空 DeleteBinaryTree(root->left); // 删除左子树 a DeleteBinaryTree(root->right); // 删除右子树 b c delete root; d 完全二叉树的顺序存储结构 当需要二叉树紧凑存储, 并且在处理过程中, 二叉树结构的大小和形状不发生动态变化时, 可以采用顺序的方法存储 用顺序存储结构表示完全二叉树 按层次顺序将一棵有 n 个结点的完全二叉树的所有结点从 0 到 n-1 编号, 就得到结点的一个线性序列 用顺序法存储二叉树, 就是要把所有结 点按照一定的次序顺序存储到一片连续 的存储单元中
9 完全二叉树的下标公式 完全二叉树中除最下面一层外, 各层都被结点充满了, 每一层结点个数恰是上一层结点个数的两倍 因此, 从一个结点的编号就可以推知它的父母, 左 右子女, 兄弟等结点的编号 当 2i+1<n 时, 结点 i 的左子女是结点 2i+1, 否则结点 i 没有左子女 当 2i+2<n 时, 结点 i 的右子女是结点 2i+2, 否则结点 i 没有右子女 5.4 二叉搜索树 二叉搜索树 (BST) 或者是一棵空树 ; 或者是具有下列性质的二叉树 : 对于任何一个结点, 设其值为 K, 则该结点的左子树 ( 若不空 ) 的所有结点的值都小于 K; 右子树 ( 若不空 ) 的所有结点的值都大于或等于 K; 而且它的左右子树也分别为二叉搜索树 二叉搜索树的性质 : 按照中序周游将各结点打印出来, 将得到按照由小到大的排列 二叉搜索树 中序序列 :20,30,32,35,40,50,80,85,88,90 二叉搜索树 二叉搜索树的搜索过程 : 从根结点开始, 在二叉搜索树中检索值 K 如果根结点储存的值为 K, 则检索结束 如果 K 小于根结点的值, 则只需检索左子树 如果 K 大于根结点的值, 就只检索右子树 这个过程一直持续到找到 K 或者遇上叶子结点 如果遇上叶子结点仍没有发现 K, 就不存在 二叉搜索树的插入 向二叉搜索树里插入新结点, 要保证插入后仍符合二叉搜索树的定义 插入过程为 : 用待插入结点与树根比较, 若待插入的关键值小于树根的关键值, 就进入左子树, 否则进入右子树 在子树里又与子树根比较, 如此下去, 直到将新结点插入到二叉树的叶子结点位置 二叉搜索树的插入 void BinarySearchTree<T>::InsertNode(root, newpointer) { pointer=root; while ( pointer 非空 ) { if ( newpointer->value() == pointer->value() ) return ; // 比较 else if ( newpointer->value() < pointer->value() ) { if ( pointer 左为空 ) { 插在左子树 ; return; 50 else 往左走 ; else{ if ( pointer 右为空 ) { 插在右子树 ; return; else 往右走 ;
10 二叉搜索树的插入 void BinarySearchTree<T>::InsertNode( BinaryTreeNode<T>* root, BinaryTreeNode<T>* newpointer) { BinaryTreeNode<T>* pointer=null; if (root==null) { Initialize(newpointer); return; else pointer=root; while (pointer!= NULL) { if ( newpointer->value() == pointer->value() ) return ; else if (newpointer->value() < pointer->value() ) { if ( pointer->leftchild() == NULL) { pointer->left=newpointer; return; 50 else pointer = pointer->leftchild(); else{ if ( pointer->rightchild() == NULL) { pointer->right=newpointer; return; else pointer = pointer->rightchild(); 创建二叉搜索树 对于给定的关键码集合, 为建立二叉搜索树, 可以从一个空的二叉搜索树开始, 将关键码一个个插进去 将关键码集合组织成二叉搜索树, 起到了对集合里的关键码进行排序的作用, 按中序周游二叉搜索树, 就能得到排好的关键码序列 二叉搜索树的删除 在二叉搜索树里删除结点时, 不是把以这个结点为根的子树都删除掉, 只是删除一个结点, 并且还要保持二叉搜索树的性质 设 p,p1,r 是指针变量,p 指向要删除的结点, p1 指向 p 的父结点, 删除过程分为两种情况 : 没有左子树 有左子树 没有左子树 若结点 p 没有左子树, 则用右子树的根代替被删除的结点 p 有左子树若 p 有左子树, 则在左子树里找中序周游的最后一个结点 r, 将 r 的右指针置成指向 p 的右子树的根, 用结点 p 的左子树的根去代替被删除的结点 p 堆与优先队列 最小值堆 : 最小值堆是一个关键码序列 {K 0,K 1, K n-1, 它具有如下特性 : K i K 2i+1 (i=0,1,, n/2-1) K i K 2i 十 2 例如 :(05,23,16,68,73,72,71,94) 类似可以定义最大值堆
11 堆的性质 堆是一个完全二叉树, 可以用数组表示 堆中存储的数据局部有序 父与子之间的值存在某种联系 兄弟之间没有必然联系 (05,23,16,68,73,72,71,94) class MinHeap { private: T* heaparray; // 存放堆数据的数组 int CurrentSize; // 当前堆中元素数目 int MaxSize; // 堆所能容纳的最大元素数目 void BuildHeap(); // 建堆 public: MinHeap(const int n); virtual ~MinHeap(){delete []heaparray;; bool isleaf(int pos) const; int leftchild(int pos) const; int rightchild(int pos) const; int parent(int pos) const; bool Remove(int pos, T& node); bool Insert(const T& newnode); T& RemoveMin(); void SiftUp(int position); void SiftDown(int left); 堆的类定义 建堆过程 假设根的左 右子树都已是堆, 并且根的元素名为 R 有两种可能 : (1) R 的值小于或等于其两个子女, 此时堆已完成 ; (2) R 的值大于其某一个或全部两个子女的值, 此时 R 应与两个子女中值较小的一个交换, 结果得到一个堆, 除非 R 仍然大于其新子女的一个或全部的两个 这种情况下, 只需继续将 R 拉下来 的过程, 直至到达某一层使它小于它的子女, 或者成为叶结点
12 template<t> MinHeap<T>::MinHeap(const int n) { if (n<=0) return; CurrentSize = 0; MaxSize = n; // 初始化堆容量为 n heaparray = new T[MaxSize]; // 创建堆空间 // 此处进行堆元素的赋值工作 BuildHeap( ); bool MinHeap<T>::isLeaf(int pos) const { return (pos>=currentsize/2)&&(pos<currentsize); ========================================== int MinHeap<T>::leftchild(int pos) const { return 2*pos+1 int MinHeap<T>::rightchild(int pos) const { return 2*pos+2; ================================= int MinHeap<T>::parent(int pos) const { return (pos-1)/2; void MinHeap<T>::SiftDown(int position) { int i=position; // 标识父结点 int j=2*i+1; // 标识关键值较小的子结点 筛选法 建初堆 从第一个有子女的结点 heaparray[currentsize/2-1] T temp=heaparray[i]; // 保存父结点 while(j<currentsize){ // 过筛 if ((j<currentsize-1) && (heaparray[j]>heaparray[j+1])) j++; //j 指向数值较小的子结点 if(temp>heaparray[j]) { heaparray[i]=heaparray[j]; i=j; j=2*j+1; // 向下继续 //end if i else break; //end if j heaparray[i]=temp; 开始, 自底向上逐步将以各结点为根的子树调整成堆 void MinHeap<T>::BuildHeap() { // 反复调用筛选函数, for (int i=currentsize/2-1; i>=0; i--) SiftDown(i);
13 插入新元素 bool MinHeap<T>::Insert(const T& newnode){ // 向堆中插入新元素 newnode if (CurrentSize == MaxSize) // 堆空间已经满 return false; heaparray[currentsize] = new Node(); SiftUp(CurrentSize); // 向上调整 CurrentSize++; 向上筛选调整堆 void MinHeap<T>::SiftUp(int position) { // 从 position 开始调整, 使序列成为堆 int temppos = position; T temp = heaparray[temppos]; while((temppos>0)&&(heaparray[parent(temppos)]>temp)) { heaparray[temppos] = heaparray[parent(temppos)]; temppos = parent(temppos); heaparray[temppos] = temp; 移出最小值 ( 优先队列出队 ) template<t> T& MinHeap<T>::RemoveMin( ) { if(currentsize==0) { cout<<"can't Delete"; exit(1); else { swap(0,--currentsize); if (CurrentSize>1) SiftDown(0); return heapsize[currentsize]; 删除元素 bool MinHeap<T>::Remove(int pos, T& node) { if((pos<0) (pos>=currentsize)) return false; node = heaparray[pos]; heaparray[pos]=heaparray[--currentsize]; if (heaparray[parent(pos)] > heaparray[pos] ) SiftUp(pos); else SiftDown(pos); return true; 建堆效率 由于堆有logn 层深, 插入结点 删除普通元素和删除最小元素的平均时间代价和最差时间代价都是 ( logn) 建堆的时间复杂度为 (nlogn) 优先队列 优先队列是一种有用的数据结构 它是 0 个或多个元素的集合 每个元素有一个关键码值, 主要操作有查找 插入和删除 优先队列的特点 : 支持从一个集合中快速查找并移出具有最大值或最小值的元素 最小优先队列适于查找与删除最小元素 ; 最大优先队列适于查找与删除最大元素
14 优先队列的实现 采用无序线性表或有序线性表缺点 : 效率慢 采用堆是一种较好的方案 5.6 Huffman 树及其应用 要求给出一个具有 n 个外部结点的扩充二叉树 该二叉树每个外部结点 K i 有一个 w i 与之对应, 作为该外部结点的权 这个扩充二叉树的叶结点带权外部路径长度总和最小 n 1 wl i i i 0 权越大的叶结点离根越近 ; 如果某个叶的权较小, 可能就会离根较远 建立 Huffman 编码树 首先, 按照 权 将字母排为一列 然后, 拿走前两个字母 ( 权 最小的两个字母 ), 再将它们标记为 Huffman 树的树叶, 将这两个树叶标为一个分支结点的两个子女, 而该结点的权即为两树叶的权之和 将所得 权 放回序列中, 使 权 的顺序保持 重复上述步骤直至序列中只剩一个元素, 则 Huffman 树建立完毕 前缀编码 在编码集合中, 任何字符的编码都不是另外一个字符编码的前缀, 这种编码叫作前缀编码 这种前缀特性保证了代码串被反编码时, 不会有多 种可能 例如, 对于上面 8 个字符, 编码为 Z(111100), K(111101), F(11111), C(1110), U(100), D(101), L(110), E(0) 这是一种前缀编码, 对于代码 , 可以翻译出唯 一的字符串 EEEL
15 Huffman 编码树的应用 设 D={d 0,,d n-1, W={W 0,,W n-1 D 为需要编码的字符集合,W 为 D 中各字符出现的频率, 要对 D 里的字符进行二进制编码, 使得 : 通信编码总长最短 若 d i d j, 则 d i 的编码不可能是 d j 的编码的开始部分 ( 前缀 ) Huffman 编码树的应用 利用 Huffman 编码 : 用 d 0,d 1,,d n-1 作外部结点,W 0,W 1,,W n-1 作外部结点的权, 构造具有最小带权外部路径长度的扩充二叉树 把从每个结点引向其左子女的边标上号码 0, 把从每个结点引向其右子女的边标上号码 1 从根到每个叶子的路径上的号码连接起来就是这个叶子代表的字符的编码 各字符的二进制编码为 : d 0 : d 1 : d 2 : d 3 :10110 d 4 :0100 d 5 :010l d 6 :1010 d 7 :000 d 8 : 001 d 9 :011 d 10 :100 d 11 :110 d 12 :111 出现频率越大的字符其编码越短 Huffman 编码树的应用 用 Huffman 算法构造出的扩充二叉树给出了各字符的编码, 同时也用来译码 从二叉树的根开始, 用需要译码的二进制位串中的若干个相邻位与二叉树边上标的 0,1 相匹配, 确定一条到达树叶的路径 一旦到达树叶, 则译出了一个字符, 再回到树根, 从二进制位串中的下一位开始继续译码 class HuffmanTree { private: public: HuffmanTreeNode<T>* root; Huffman 树类 void MergeTree(HuffmanTreeNode<T> &ht1, HuffmanTreeNode<T> &ht2, HuffmanTreeNode<T>* parent); void DeleteTree(HuffmanTreeNode<T>* root); HuffmanTree(T weight[],int n); virtual ~HuffmanTree(){DeleteTree(root);;
16 Huffman 树的构造 HuffmanTree<T>::HuffmanTree(T weight[], int n) { MinHeap<HuffmanTreeNode<T>> heap(n); HuffmanTreeNode<T> *parent,&firstchild,&secondchild; HuffmanTreeNode<T>* NodeList=new HuffmanTreeNode<T>[n]; for(int i=0;i<n;i++){ NodeList[i].element=weight[i]; NodeList[i].parent=NodeList[i].left=NodeList[i].right=NULL; heap.insert(nodelist[i]); //end for for(i=0;i<n-1;i++) { parent=new HuffmanTreeNode<T>; firstchild=heap.removemin(); secondchild=heap.removemin(); MergeTree(firstchild,secondchild,parent); heap.insert(*parent); root=parent; delete []NodeList; 本章作业 教材 P132 4,6,13,14,16,18, 本章上机作业 教材 P133-P134 第 1 题 :2 第 2 题 :
PowerPoint 演示文稿
数据结构与算法 ( 五 ) 张铭主讲 采用教材 : 张铭, 王腾蛟, 赵海燕编写高等教育出版社,2008. 6 ( 十一五 国家级规划教材 ) http://www.jpk.pku.edu.cn/pkujpk/course/sjjg 第五章 的概念 的抽象数据类型 深度优先搜索 宽度优先搜索 的存储结构 D B A E G C H F I 二叉搜索树 堆与优先队列 Huffman 树及其应用 2 的定义
PowerPoint 演示文稿
数据结构与算法 ( 五 ) 张铭主讲 采用教材 : 张铭, 王腾蛟, 赵海燕编写高等教育出版社,2008. 6 ( 十一五 国家级规划教材 ) http://www.jpk.pku.edu.cn/pkujpk/course/sjjg 第五章 的概念 的抽象数据类型 深度优先搜索 宽度优先搜索 的存储结构 D B A E G C H F I 二叉搜索树 堆与优先队列 Huffman 树及其应用 2 5.2
PowerPoint Presentation
数 据 结 构 与 算 法 ( 六 ) 张 铭 主 讲 采 用 教 材 : 张 铭, 王 腾 蛟, 赵 海 燕 编 写 高 等 教 育 出 版 社,2008. 6 ( 十 一 五 国 家 级 规 划 教 材 ) http://www.jpk.pku.edu.cn/pkujpk/course/sjjg A 第 6 章 树 B 树 的 定 义 和 基 本 术 语 树 的 链 式 存 储 结 构 J H
204 */ InitiateStack s ; /* s */ i = n; t = p = new node; /* */ p->data = postorder[i]; while i > q = new node; if parent[i - ] == postorder[i] S,T S
28 4 Vol.28 No.4 4 204 2 JOURNAL OF NANTONG VOCATIONAL UNIVERSITY Dec. 204!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! doi:0.3969/j.issn.008-5327.204.04.024 唐自立 ( 苏州大学计算机科学与技术学院, 江苏苏州 25006)
C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1
C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 月 3 日 1 1 INPUTOUTPUT 1 InputOutput 题目描述 用 cin 输入你的姓名 ( 没有空格 ) 和年龄 ( 整数 ), 并用 cout 输出 输入输出符合以下范例 输入 master 999 输出 I am master, 999 years old. 注意 "," 后面有一个空格,"." 结束,
<4D6963726F736F667420506F776572506F696E74202D20332D322E432B2BC3E6CFF2B6D4CFF3B3CCD0F2C9E8BCC6A1AAD6D8D4D8A1A2BCCCB3D0A1A2B6E0CCACBACDBEDBBACF2E707074>
程 序 设 计 实 习 INFO130048 3-2.C++ 面 向 对 象 程 序 设 计 重 载 继 承 多 态 和 聚 合 复 旦 大 学 计 算 机 科 学 与 工 程 系 彭 鑫 [email protected] 内 容 摘 要 方 法 重 载 类 的 继 承 对 象 引 用 和 拷 贝 构 造 函 数 虚 函 数 和 多 态 性 类 的 聚 集 复 旦 大 学 计 算 机 科 学
untitled
1 Outline 數 料 數 數 列 亂數 練 數 數 數 來 數 數 來 數 料 利 料 來 數 A-Z a-z _ () 不 數 0-9 數 不 數 SCHOOL School school 數 讀 school_name schoolname 易 不 C# my name 7_eleven B&Q new C# (1) public protected private params override
FY.DOC
高 职 高 专 21 世 纪 规 划 教 材 C++ 程 序 设 计 邓 振 杰 主 编 贾 振 华 孟 庆 敏 副 主 编 人 民 邮 电 出 版 社 内 容 提 要 本 书 系 统 地 介 绍 C++ 语 言 的 基 本 概 念 基 本 语 法 和 编 程 方 法, 深 入 浅 出 地 讲 述 C++ 语 言 面 向 对 象 的 重 要 特 征 : 类 和 对 象 抽 象 封 装 继 承 等 主
ebook39-5
5 3 last-in-first-out, LIFO 3-1 L i n e a r L i s t 3-8 C h a i n 3 3. 8. 3 C + + 5.1 [ ] s t a c k t o p b o t t o m 5-1a 5-1a E D 5-1b 5-1b E E 5-1a 5-1b 5-1c E t o p D t o p D C C B B B t o p A b o
新版 明解C++入門編
511!... 43, 85!=... 42 "... 118 " "... 337 " "... 8, 290 #... 71 #... 413 #define... 128, 236, 413 #endif... 412 #ifndef... 412 #if... 412 #include... 6, 337 #undef... 413 %... 23, 27 %=... 97 &... 243,
PowerPoint 演示文稿
张铭 数据结构与算法 数据结构与算法 ( 九 ) 张铭主讲 采用教材 : 张铭, 王腾蛟, 赵海燕编写高等教育出版社,2008 6 ( 十一五 国家级规划教材 ) http://wwwjpkpkueducn/pkujpk/course/sjjg 第 9 章 91 主存储器和外存储器 92 文件的组织和管理 931 置换选择排序 932 二路外排序 933 多路归并 选择树 2 张铭 数据结构与算法
第一章三角函数 1.3 三角函数的诱导公式 A 组 ( ) 一 选择题 : 共 6 小题 1 ( 易诱导公式 ) 若 A B C 分别为 ABC 的内角, 则下列关系中正确的是 A. sin( A B) sin C C. tan( A B) tan C 2 ( 中诱导公式 ) ( ) B. cos(
第一章三角函数 1. 三角函数的诱导公式 A 组 一 选择题 : 共 6 小题 1 ( 易诱导公式 ) 若 A B C 分别为 ABC 的内角 则下列关系中正确的是 A. sin( A B) sin C C. tan( A B) tan C ( 中诱导公式 ) B. cos( B C) cos A D. sin( B C) sin A sin60 cos( ) sin( 0 )cos( 70 ) 的值等于
数据结构与算法(Python)-00/引子
物理 结构 逻辑 结构 运算 -06/ 树及算法 刘云淮 [email protected] http://www.yunhuai.net/dsa2018/dsa2018 北京大学大数据科学研究中心 目录 本章目标 树的例子 实现树 二叉堆实现的优先队列 二叉树应用 树遍历 二叉搜索树 本章目标 理解树数据结构及其应用 树用于实现 ADT Map 用列表来实现树 用类和引用来实现树 以递归方式实现树
ebook39-6
6 first-in-first-out, FIFO L i n e a r L i s t 3-1 C h a i n 3-8 5. 5. 3 F I F O L I F O 5. 5. 6 5. 5. 6.1 [ ] q u e n e ( r e a r ) ( f r o n t 6-1a A 6-1b 6-1b D C D 6-1c a) b) c) 6-1 F I F O L I F ADT
2.3 链表
数据结构与算法 ( 二 ) 张铭主讲 采用教材 : 张铭, 王腾蛟, 赵海燕编写高等教育出版社,2008. 6 ( 十一五 国家级规划教材 ) https://pkumooc.coursera.org/bdsalgo-001/ 第二章线性表 2.1 线性表 2.2 顺序表 tail head a 0 a 1 a n-1 2.4 顺序表和链表的比较 2 链表 (linked list) 通过指针把它的一串存储结点链接成一个链
新・解きながら学ぶJava
481! 41, 74!= 40, 270 " 4 % 23, 25 %% 121 %c 425 %d 121 %o 121 %x 121 & 199 && 48 ' 81, 425 ( ) 14, 17 ( ) 128 ( ) 183 * 23 */ 3, 390 ++ 79 ++ 80 += 93 + 22 + 23 + 279 + 14 + 124 + 7, 148, 16 -- 79 --
エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******
******************* * 关于 Java 测试试题 ******************* 問 1 运行下面的程序, 选出一个正确的运行结果 public class Sample { public static void main(string[] args) { int[] test = { 1, 2, 3, 4, 5 ; for(int i = 1 ; i System.out.print(test[i]);
算法分析与问题的计算复杂度
算法分析与问题的计算复杂度 王子辰 2016.5.20 概要 第一部分检索 算法的评价指标 平凡下界 决策树与时间复杂度 第二部分排序 冒泡排序 堆排序等排序算法 排序算法的复杂度下界 第三部分选择 选择问题的时间复杂度分析 问题之间的归约性 概要 第一部分检索 算法的评价指标 平凡下界 决策树与时间复杂度 第二部分排序 冒泡排序 堆排序等排序算法 排序算法的复杂度下界 第三部分选择 选择问题的时间复杂度分析
Guava学习之Resources
Resources 提供提供操作 classpath 路径下所有资源的方法 除非另有说明, 否则类中所有方法的参数都不能为 null 虽然有些方法的参数是 URL 类型的, 但是这些方法实现通常不是以 HTTP 完成的 ; 同时这些资源也非 classpath 路径下的 下面两个函数都是根据资源的名称得到其绝对路径, 从函数里面可以看出,Resources 类中的 getresource 函数都是基于
Microsoft PowerPoint - string_kruse [兼容模式]
Strings Strings in C not encapsulated Every C-string has type char *. Hence, a C-string references an address in memory, the first of a contiguous set of bytes that store the characters making up the string.
C++ 程序设计 OJ4 - 参考答案 MASTER 2017 年 5 月 21 日 1
C++ 程序设计 OJ4 - 参考答案 MASTER 2017 年 5 月 21 日 1 1 SWAP 1 Swap 题目描述 用函数模板的方式实现对不同数据类型的数组中的数据进行输入 从小到大排序和输出 使用如下主函数测试你的模板设计一个函数模板 Swap, 实现任意数据类型的两个数据的交换, 分别用 int 型 double 型和 char 型的数据进行测试 main 函数如下 : int main()
Microsoft Word - 01.DOC
第 1 章 JavaScript 简 介 JavaScript 是 NetScape 公 司 为 Navigator 浏 览 器 开 发 的, 是 写 在 HTML 文 件 中 的 一 种 脚 本 语 言, 能 实 现 网 页 内 容 的 交 互 显 示 当 用 户 在 客 户 端 显 示 该 网 页 时, 浏 览 器 就 会 执 行 JavaScript 程 序, 用 户 通 过 交 互 式 的
SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基
开放数据处理服务 ODPS SDK SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基础功能的主体接口, 搜索关键词 "odpssdk-core" 一些
C++ 程序设计 OJ4 - 参考答案 MASTER 2019 年 5 月 3 日 1
C++ 程序设计 OJ4 - 参考答案 MASTER 2019 年 5 月 3 日 1 1 MYQUEUE 1 MyQueue 题目描述 设计一个 MyQueue 类模板, 类模板说明如下 : template class MyQueue; template std::ostream & operator
《C语言程序设计》教材习题参考答案
教材名称 : C 语言程序设计 ( 第 1 版 ) 黄保和 江弋编著清华大学出版社 ISBN:978-7-302-13599-9, 红色封面 答案制作时间 :2011 年 2 月 -5 月 一 选择题 1. 设已定义 int a, * p, 下列赋值表达式中正确的是 :C)p=&a 2. 设已定义 int x,*p=&x;, 则下列表达式中错误的是 :B)&*x 3. 若已定义 int a=1,*b=&a;,
Two Mergeable Data Structures
Two Mergeable Data Structures Disjoint-Set 并查集 & Leftist-Tree 左偏树 1 Disjoint-Set(Union-Find Set) 并查集 N distinct elements into a collection of disjoint sets. Op1: Find which set a given element belong in
无类继承.key
无类继承 JavaScript 面向对象的根基 周爱 民 / aimingoo [email protected] https://aimingoo.github.io https://github.com/aimingoo rand = new Person("Rand McKinnon",... https://docs.oracle.com/cd/e19957-01/816-6408-10/object.htm#1193255
《C语言程序设计》第2版教材习题参考答案
教材 C 语言程序设计 ( 第 2 版 ) 清华大学出版社, 黄保和, 江弋编著 2011 年 10 月第二版 ISBN:978-7-302-26972-4 售价 :35 元 答案版本 本习题答案为 2012 年 2 月修订版本 一 选择题 1. 设已定义 int a, * p, 下列赋值表达式中正确的是 :C)p = &a A. *p = *a B. p = *a C.p = &a D. *p =
大侠素材铺
编译原理与技术 语法制导翻译 Ⅱ 计算机科学与技术学院 李诚 22/10/2018 Announcement Tutorial on Thursday (25/10/2018) 3B201, Class time Assignment review Q & A Cheng @ Compiler Fall 2018, USTC 2 主要内容 源程序 词法分析器 token 语法分析器 分析树 语义分析
Microsoft PowerPoint - 5. 指针Pointers.ppt [兼容模式]
指针 Pointers 变量指针与指针变量 Pointer of a variable 变量与内存 (Variables and Memory) 当你声明一个变量时, 计算机将给该变量一个内存, 可以存储变量的值 当你使用变量时, 计算机将做两步操作 : - 根据变量名查找其对应的地址 ; - 通过地址对该地址的变量内容进行读 (retrieve) 或写 (set) 变量的地址称为变量的指针! C++
38 47995529 威 福 髮 藝 店 桃 園 市 蘆 竹 區 中 山 里 福 祿 一 街 48 號 地 下 一 樓 50,000 獨 資 李 依 純 105/04/06 府 經 登 字 第 1059003070 號 39 47995534 宏 品 餐 飲 桃 園 市 桃 園 區 信 光 里 民
1 08414159 惠 鴻 眼 鏡 行 桃 園 市 中 壢 區 福 德 里 中 華 路 一 段 186 號 1 樓 30,000 獨 資 宋 耀 鴻 105/04/27 府 經 登 字 第 1059003866 號 2 17891110 承 元 冷 氣 空 調 工 程 行 桃 園 市 桃 園 區 中 德 里 國 際 路 1 段 98 巷 50 號 2 樓 之 4 200,000 獨 資 詹 安 平
chap07.key
#include void two(); void three(); int main() printf("i'm in main.\n"); two(); return 0; void two() printf("i'm in two.\n"); three(); void three() printf("i'm in three.\n"); void, int 标识符逗号分隔,
什么是函数式编程?
函数式编程 FUNCTIONAL PROGRAMMING [email protected] 什么是函数式编程? 真相是 从停机问题开始 Bug 假设有停机判定算法 function halting(func, input) { } return if_func_will_halt_on_input; 充分利用停机判定 function ni_ma(func) { if (halting(func,
CC213
: (Ken-Yi Lee), E-mail: [email protected] 49 [P.51] C/C++ [P.52] [P.53] [P.55] (int) [P.57] (float/double) [P.58] printf scanf [P.59] [P.61] ( / ) [P.62] (char) [P.65] : +-*/% [P.67] : = [P.68] : ,
1 Framework.NET Framework Microsoft Windows.NET Framework.NET Framework NOTE.NET NET Framework.NET Framework 2.0 ( 3 ).NET Framework 2.0.NET F
1 Framework.NET Framework Microsoft Windows.NET Framework.NET Framework NOTE.NET 2.0 2.0.NET Framework.NET Framework 2.0 ( 3).NET Framework 2.0.NET Framework ( System ) o o o o o o Boxing UnBoxing() o
中北大学常规事项财务报销操作指南
中 北 大 学 常 规 事 项 财 务 报 销 操 作 指 南 一 办 公 费 报 销 指 南 定 义 : 办 公 费 是 单 位 购 买 按 财 务 会 计 制 度 规 定 不 符 合 固 定 资 产 标 准 的 日 常 办 公 用 品 书 报 杂 志 等 支 出 通 俗 讲 是 指 办 公 场 所 使 用 的 低 值 易 耗 品 办 公 用 品 的 类 别 : 纸 薄 类 笔 尺 类 装 订 类
}; "P2VTKNvTAnYNwBrqXbgxRSFQs6FTEhNJ", " " string imagedata; if(0!= read_image("a.jpg",imagedata)) { return -1; } string rsp; ytopen_sdk m_sd
tencentyun-youtu c++ sdk for 腾讯云智能优图服务 & 腾讯优图开放平台 安装 运行环境 Linux 依赖项 - curl-7.40.0, 获取更新版本 https://github.com/bagder/curl - openssl-1.0.1k, 获取更新版本 https://github.com/openssl/openssl 构建工程 工程采用 CMake 构建 1.
C++ 程序设计 OJ9 - 参考答案 MASTER 2019 年 6 月 7 日 1
C++ 程序设计 OJ9 - 参考答案 MASTER 2019 年 6 月 7 日 1 1 CARDGAME 1 CardGame 题目描述 桌上有一叠牌, 从第一张牌 ( 即位于顶面的牌 ) 开始从上往下依次编号为 1~n 当至少还剩两张牌时进行以下操作 : 把第一张牌扔掉, 然后把新的第一张放到整叠牌的最后 请模拟这个过程, 依次输出每次扔掉的牌以及最后剩下的牌的编号 输入 输入正整数 n(n
Microsoft PowerPoint - 概率统计Ch02.ppt [Compatibility Mode]
66 随机变量的函数.5 随机变量的函数的分布 设 是一随机变量, 是 的函数, g(, 则 也是一个随机变量. 本节的任务 : 当 取值 x 时, 取值 y g 67 ( 一 离散型随机变量的函数 设 是离散型随机变量, 其分布律为 或 P { x } p (,, x x, P p p, x p 已知随机变量 的分布, 并且已知 g 要求随机变量 的分布. (, 是 的函数 : g(, 则 也是离散型随机变
Microsoft Word - 第3章.doc
Java C++ Pascal C# C# if if if for while do while foreach while do while C# 3.1.1 ; 3-1 ischeck Test() While ischeck while static bool ischeck = true; public static void Test() while (ischeck) ; ischeck
Microsoft Word - ch04三校.doc
4-1 4-1-1 (Object) (State) (Behavior) ( ) ( ) ( method) ( properties) ( functions) 4-2 4-1-2 (Message) ( ) ( ) ( ) A B A ( ) ( ) ( YourCar) ( changegear) ( lowergear) 4-1-3 (Class) (Blueprint) 4-3 changegear
概述
OPC Version 1.6 build 0910 KOSRDK Knight OPC Server Rapid Development Toolkits Knight Workgroup, eehoo Technology 2002-9 OPC 1...4 2 API...5 2.1...5 2.2...5 2.2.1 KOS_Init...5 2.2.2 KOS_InitB...5 2.2.3
