数据结构编程实验——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班 姓名:盛 ...
随机推荐
- 2018软工实践第八次作业-团队项目UML设计
团队信息 队员姓名与学号 学号 姓名 博客链接 124 王彬(组长) 点击这里 206 赵畅 点击这里 215 胡展瑞 点击这里 320 李恒达 点击这里 131 佘岳昕 点击这里 431 王源 点击 ...
- angularJS1笔记-(6)-自定义过滤器
html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- iOS- 什么是GitHub?关于它的自我介绍「初识 GitHub」
1 前言 我一直认为 GitHub 是程序员必备技能,程序员应该没有不知道 GitHub 的才对,我当初接触 GitHub 也大概工作了一年多才开始学习使用,我读者里很多是初学者,而且还有很多是在校大 ...
- DispatcherServlet的作用
DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好 ...
- 深入理解JAVA集合系列四:ArrayList源码解读
在开始本章内容之前,这里先简单介绍下List的相关内容. List的简单介绍 有序的collection,用户可以对列表中每个元素的插入位置进行精确的控制.用户可以根据元素的整数索引(在列表中的位置) ...
- 深入理解JAVA集合系列三:HashMap的死循环解读
由于在公司项目中偶尔会遇到HashMap死循环造成CPU100%,重启后问题消失,隔一段时间又会反复出现.今天在这里来仔细剖析下多线程情况下HashMap所带来的问题: 1.多线程put操作后,get ...
- maven编译,控制台中文乱码解决方案
如下图,在使用maven运行后,在控制台看到中文展示乱码 出现这个的原因是源码使用UTF-8,但是maven编译的时候使用GBK标准,如下图 为了让maven编译的时候使用UTF-8标准,使用在p ...
- soap 简单的例子
首先确保你的soap模块开启 客户端代码 <?php try { $client = new SoapClient(null, array('location' =>"http: ...
- htop操作方法
为什么 Linux 的 htop 命令完胜 top 命令? 在 Linux 系统中,top 命令用来显示系统中正在运行的进程的实时状态,它显示了一些非常有用的信息,比如 CPU 利用情况.内存消耗情况 ...
- ucontext-人人都可以实现的简单协程库
ucontext的介绍 http://blog.csdn.net/qq910894904/article/details/41911175 协程的介绍 https://en.wikipedia.org ...