数据结构编程实验——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班 姓名:盛 ...
随机推荐
- HDU 4405 Aeroplane chess 期望dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4405 Aeroplane chess Time Limit: 2000/1000 MS (Java/ ...
- ThoughtWorks.QRCode类库
ThoughtWorks.QRCode一个二维码生成类库.
- centos7开机出现try again to boot into default maintenance give root password for maintenance
开启centos7出现下面两句话,然后直接输出root密码,就可以登录,但是登录后,发现一些文字显示出来的是乱码 try again to boot into default maintenanceg ...
- requests爬取知乎话题和子话题
zhihu.py # *_*coding:utf-8 *_* import pymysql import requests from lxml import etree from requests_t ...
- Nmap用法实例
<给Linux系统/网络管理员的nmap的29个实用例子> https://linux.cn/article-2561-1.html
- [PPT] PPT 录制视频功能.
1. 需要PPT 里面增加进截图, 发现还不如 直接插入视频合理 本来想了一种方式是 使用 screen to gif 的工具 生成gif 来处理. 后来 发现ppt 里面自带一个 屏幕录制功能. 2 ...
- DotNetty 跨平台的网络通信库
长久以来,.Net开发人员都非常羡慕Java有Netty这样,高效,稳定又易用的网络通信基础框架.终于微软的Azure团队,使用C#实现的Netty的版本发布.不但使用了C#和.Net平台的技术特点, ...
- multi thread for Java
I try to do a testing for HashTable Sychronized behavior today. As an Sychronized Object, HashTable ...
- (暂时弃坑)(半成品)ACM数论之旅18---反演定理 第二回 Mobius反演(莫比乌斯反演)((づ ̄3 ̄)づ天才第一步,雀。。。。)
莫比乌斯反演也是反演定理的一种 既然我们已经学了二项式反演定理 那莫比乌斯反演定理与二项式反演定理一样,不求甚解,只求会用 莫比乌斯反演长下面这个样子(=・ω・=) d|n,表示n能够整除d,也就是d ...
- app流畅度测试--使用SM
通过测量应用的帧率FPS并不能准确评价App的流畅度,FPS较低并不能代表当前App在UI上界面不流畅,而1s内VSync这个Loop运行了多少次更加能说明当前App的流畅程度. 那么我们可以直接在A ...