数据结构编程实验——chapter10-应用经典二叉树编程
二叉树不仅结构简单、节省内存,更重要是是这种结构有利于对数据的二分处理。之前我们提过,在二叉树的基础上能够派生很多经典的数据结构,也是下面我们将进行讨论的知识点:
(1) 提高数据查找效率的二叉排序树。
(2) 优先队列的最佳存储结构的二叉堆。
(3) 兼具二叉排序树和二叉堆性质的树堆。
(4) 用于算法分析的数据编码的哈夫曼树。
一. 二叉排序树
二叉排序树主要用于高效率查找。查找方法一般有三种:顺序查找、二分查找和二叉排序树查找。二叉排序树又可以分成多种类型。这里不同的查找方法,衡量他们的关键就是查找效率,往往越是复杂的构造二叉排序树,在查找数据的效率方面越优良。
具有以下性质的非空二叉树,称为二叉排序树:
1) 若根节点的左子树不空,则左子树的所有节点值均小于根节点值。
2) 若根节点的右子树不空,则右子树的所有节点值均不小于根节点值。
3) 根节点的左右子树也分别是二叉排序树。
容易看到,根据二叉排序树的构造机制,查找某个元素的效率就取决于所构造的二叉排序树的深度。深度越小,效率越高。二叉排序树有如下三种类型:
i) 普通二叉排序树:边输入边构造的二叉排序树,树的深度取决于输入的序列。
ii) 静态二叉排序树:按照二分查找的方法构造出的二叉排序树,近似丰满,深度约为logn。但是这种树需要离线构建,即输入数据后一次性建树,不方便动态维护。
iii) 平衡树:再插入和删除过程中一直保持左右子树的高度至多相差1的平衡条件,且能够保证树的深度是logn.
Ex1(poj2309):
给出一种无穷满二叉排序树的机制,其叶子节点是无穷的奇数序列:1、3、5……然后1、3的父节点是右儿子序号减左儿子序号.这样能够形成倒数第二层的节点,然后按照同样的机制形成上面那层节点。然后给出一个节点序号x,编程计算以该节点为根的二叉排序树的最小编号以及最大编号。
既然题目给出的是无穷满二叉排序树,我们就能够充分利用二叉排序树和满二叉树的性质。对于以x为根的子树,如果我们知道这棵树的层数k(层数从0开始计数),根据满二叉树的性质,该子树有2^(k+1) – 1个节点。x的左子树的节点编号都是小于x的,x的左子树也是一个满二叉树,节点数是2^k – 1,因此我们能看到,x的左子树的编号区间是[min , x - 1],这个区间含有的整数就是x的左子树的节点数,即有x-1-min+1=2^k – 1成立。即有min = x – 2^k +1.对称的,对于最大标号的节点,是完全一样的分析思路。则有max = x + 2^k – 1.
下面我们需要解决的问题就剩下如何计算根节点为x的树的层数。根据这棵无限二叉排序树的机制,我们容易看到规律,x除以2^k是奇数的时候,k便是层数。我们将整数x视为二进制形式a[n]a[n-1]…a[0],再从按权展开的形式去考察这个整数x,我们反复除以2,发现当遇到二进制形式右侧第一个1的时候,整数x变成了奇数。即我们有这样的结论,二进制数x右侧第一个1所在位置的权值2^k,k便是树的层数。
而这样的2^k我们可以通过位运算x&(-x)快速得到。
参考代码如下:
#include<iostream>
using namespace std;
long long lowbit(long long x){
return x & (-x);
}
int main(){
long long n , x;
cin >> n;
for(int i = ;i < n;i++){
cin >> x;
cout << x - lowbit(x) + <<' ' << x + lowbit(x) - <<endl;
}
}
二.二叉堆.
二叉堆是一棵满足下列性质的完全二叉树:如果某节点有孩子,则根节点的值都小于孩子节点的值,这样的二叉堆我们称之位小根堆。反之,如果根节点的值都大于孩子节点的值,我们称之为大根堆。
基于二叉堆的性质,我们非常好获得整个堆的最大元素和最小元素,因此二叉堆经常用于优先队列的存储结构。因为优先队列的删除操作正是删除一个线性序列中优先级最大或者最小的元素。
下面我们便开始讨论这样一个数据结构的各种操作。
1) 小根堆的插入操作:
假设我们原本有一个满足二叉堆性质的结构(在程序中我们用线性结构存储这样一个特殊的完全完全二叉树),当需要加入一个新的节点进入小根堆的时候,我们将其加入到小根堆的最后面,然后根据其节点序号(注意和节点权值不一样)来得到其父节点的序号,进而访问其权值,进行比较并进行交换,然后进行迭代操作一直向上走。
Int k = ++top;
Heap[k] = 被插入元素的权值.
While(k > ){//k=0到达根节点,是迭代的终结点.
int t = (k - )/;
if(heap(k )< heap(t)){
swap(heap[k] , heap[t])
k = t;
}
else break;
}
2) 小根堆的删除操作
在堆中删除最小元素,即删除heap[0],然后将二叉堆中节点序号最大的节点移动到根节点,然后从根节点往下进行维护小根堆性质的操作。
if(top){
int temp = heap[];
int k = ;
heap[k] = heap[top--];
while(( * k + ) <= top){
int t = *k + ;
if(t < top && heap[t + ] < heap[t]) t++;
if(heap[k] > heap[t]){//当前节点的最小孩子比当前节点的权值小,需要交换
swap(heap[k] , heap[t]);
k = t;
}
else break;
}
}
else output "empty heap"
ex1(zoj2724):
消息队列是操作系统的基础,现在给出两种类型的指令:
1)GET指令:获取消息队列中优先级最高的指令信息(包括指令名称和指令参数)。
2)PUT指令:往消息队列中添加指令,包括指令名称,指令参数和优先值。注意这里优先值越小优先级越大,二者相同时,较早进入消息队列的优先级高。
典型的优先队列的题目,这里我们在用二叉堆实现的时候,需要手写一个函数用于二叉堆元素权值的比较。输入的时候我们为每个节点顺序标号,节点信息我们存储在一个缓存区,而二叉堆用于存储节点序号。在插入删除的时候,我们利用存储的节点序号这一索引,在缓冲区找到对应节点的信息,进行比较。
参考代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = + ;//60000条指令
const int maxs = ;
struct info{
char name[maxs];
int para;
int pri , t;
}p[maxn];
int heap[maxn];
int top , used;
int compare(int a , int b){//ad额优先级高发返回-1 ,否则返回1
if(p[a].pri < p[b].pri) return -;
if(p[a].pri > p[b].pri) return ;
if(p[a].t < p[b].t) return -; //优先级相等,看时间戳
if(p[a].t > p[b].t) return ;
}
int main(){
used = ;
top = ;//堆尾指针,指向堆数组最后一个元素的后面。
int cnt = ;
char s[maxs];
while(scanf("%s" , s) != EOF){
getchar();
if(!strcmp(s , "GET")){//输入GET,进行删除操作
if(top){
printf("%s %d\n" , p[heap[]].name , p[heap[]].para);
int k = ;
heap[k] = heap[--top];
while( * k + < top){//这里注意取值范围,top是指堆的尾部指针的后面那个一个,因此这里就不取等号
int t = * k + ;
if(t < top && compare(heap[t + ] , heap[t] < )) t++;
if(t < top && compare(heap[t] , heap[k]) < ){
swap(heap[t] , heap[k]);
k = t;
}
}
}
else printf("EMPTY QUEUE!\n");
}
else{
scanf("%s %d %d" , p[cnt].name , &p[cnt].para , &p[cnt].pri);
p[cnt].t = cnt;
int k = top++;
heap[k] = cnt++;//堆尾放入当前节点序号
while(k > ){//第一个点不走这个
int t = (k - )/;
if(compare(heap[k] , heap[t]) < ){
swap(heap[k] , heap[t]);
k = t;
}
else break;
}
}
}
return ;
}
数据结构编程实验——chapter10-应用经典二叉树编程的更多相关文章
- 20145212 实验五《Java网络编程》
20145212 实验五<Java网络编程> 一.实验内容 1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: 2.利用加解密代码包,编译运行代码,一人加密,一人解密: 3.集成 ...
- 20145325张梓靖 实验五 "JAVA的网络编程"
20145325张梓靖 实验五 "JAVA的网络编程" 实验内容 使用 JVAV语言 进行网络编程 对明文进行加密 设计过程 我完成的是客户端,服务端同伴 20145308刘昊阳 ...
- 20145210实验五《Java网络编程》
20145210实验五<Java网络编程> 实验内容 1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: 2.利用加解密代码包,编译运行代码,一人加密,一人解密: 3.集成代码, ...
- 20145237 实验五《Java网络编程》
20145237 实验五<Java网络编程> 一.实验内容 •1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: •2.利用加解密代码包,编译运行代码,一人加密,一人解密: •3 ...
- 20145221 《Java程序设计》实验报告五:网络编程及安全
20145221 <Java程序设计>实验报告五:网络编程及安全 实验要求 掌握Socket程序的编写 运行TCP代码包,结对进行,一人服务器,一人客户端 掌握密码技术的使用 利用加解密代 ...
- 20155229——实验五《 Java网络编程及安全》
20155229--实验五 Java网络编程及安全 实验内容 实验一: 两人一组结对编程: 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA ...
- 20145312 实验五 《Java网络编程》
20145312 实验五<Java网络编程> 一. 实验内容及要求 实验内容: 运行下载的TCP代码,结对进行,一人服务器,一人客户端: 利用加解密代码包,编译运行代码,一人加密,一人解密 ...
- 20145312 实验五《Java网络编程》
20145312 实验五<Java网络编程> 一. 实验内容及要求 实验内容: 运行下载的TCP代码,结对进行,一人服务器,一人客户端: 利用加解密代码包,编译运行代码,一人加密,一人解密 ...
- 20175316 盛茂淞 2018-2019-2 《Java程序设计》实验五 《网络安全与编程》 实验报告
20175316 盛茂淞 2018-2019-2 <Java程序设计>实验五 <网络安全与编程> 实验报告 一.实验报告封面 课程:Java程序设计 班级:1753班 姓名:盛 ...
随机推荐
- c++工厂模式(Factory method)
下面以女娲造黑人,白人,黄种人的例子来介绍一下工厂模式. 1.工厂的接口,相当于造人工厂总部. class IHumanFactory { public: IHumanFactory(void) { ...
- 福大软工1816 · 评分结果 · Alpha冲刺答辩总结
作业地址:https://edu.cnblogs.com/campus/fzu/Grade2016SE/homework/2462 作业提交准则 按时交 - 有分 晚交 - 0分 迟交一周以上 - 倒 ...
- python learning Exception & Debug.py
''' 在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因.在操作系统提供的调用中,返回错误码非常常见.比如打开文件的函数open(),成功时返 ...
- P4安装
P4安装篇 ubuntu 14.04为例子 一.首先要fork到自己的github里面 源码目录 https://github.com/p4lang/p4factory 然后fork到自己的githu ...
- vue.js 中slot 用处大(转载)
什么是组件? 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有 ...
- 使用mdadm创建磁盘RAID10整列,RAID5出现故障,自动替换硬盘
首先需了解mdadm的参数使用 . 第一步: 先在虚拟机中添加四块硬板 第二步:使用mdadm命令创建RAID10名称为"/dev/md0" -C代表创建操作,v 显示创建过程,- ...
- 对TCP/IP网络参数进行调整
对TCP/IP网络参数进行调整 调整TCP/IP网络参数,可以增强抗SYN Flood的能力,命令如下所示:# echo 'net.ipv4.tcp_syncookies = 1' >> ...
- poi读取Excel文件和图片
首先得说一下,Excel文件是有03版和07版的区别的,也就是.xls和.xlsx,这两个文件需要分开读取. 其它的废话就不说了,直接贴代码: package util; import java.io ...
- isset与empty 的区别
isset()与empty()函数的区别,isset()只需要验证一个值是否存在: 而empty()不但需验证这个值是否存在,还需检验它的值是否非空和非0: 注:isset()只检验一个变量是否已经设 ...
- 【转载】JSP 获取真实IP地址的代码
JSP 获取真实IP地址的代码 在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的. 但是在通过了 Apache,Squid ...