关于树结构的非线性表编程在数据结构中可以说占据了半壁江山,其中涉及的知识点繁杂,但也是数据结构体现运算优化的核心所在,下面我们将较为初步且系统得讨论数据结构中一系列有关树的表示。

首先我们再次明确树的形式化概念:

树是n个节点的有限集合,这个集合满足以下的条件:

1)     有且仅有一个节点没有前件。

2)     除根外,其他的所有节点都有且仅有一个前件。

3)     除去根以外,其他每个节点都通过唯一的路径连接根上。每个节点的前件称为该节点的父节点,后件称为该节点的子节点。

这篇文章主要包含如下4个知识点:

(1)   用树的遍历求解层次性问题。

(2)   用树结构支持并查集。

(3)   用树状数组同济子树权和。

(4)   用四叉树求解二维空间问题。

首先我们讨论树在计算机中的表示,这不仅仅在处理一些数据结构的题目中很重要,在一些树形动态规划的问题上,我们首先要完成的也是树的表示。

方法1:双亲表示法。

在高级语言中我们容易操作和定义的是线性结构,即数组这样的数据结构,因此我们考虑非线性结构的程序语言表示的时候,基本原则就是将其向线性数据结构转化。给出一个树结构,根据树的定义我们知道,除了根节点,每个节点有且仅有一个父节点。因此我们定义双亲表示数组f[].其中f[i]表示节点i的父节点的节点序号。

方法2:多重链表法

这里我们常常用到c++语言stl库中的vector类。对于给定的一棵树,我们利用”vector<int> tree[n]”这样一条语句,然后定义tree[i].push_back(j)表示j作为i的一个子节点。通俗来说,这里我们将树结构扩成了一个二维数组,而利用vector类则是为了更好的节约空间资源。

一般题目中,输入的树结构往往是对于给定的n个节点的树结构,输入n-1个有序节点对用于表示父子关系,这时候往往用方法2表示树是比较常见的,而往往在一般题目中,需要多种表示方法并用,因为各个树结构的表示方式都有各自的优点(访问树自身某方面的信息时比较快)。

用树的遍历求解层次性问题:

最近公共祖先问题:

给出一个n节点的树结构的n-1对有序顶点对<x , y>,表示树结构中的一条边且x是父节点,y是子节点。最后输入一对节点序号<a, b>,编写程序

最近公共祖先代码如下:

//poj 1330.

#include<cstdio>

#include<cstring>

#include<vector>

using namespace std;

const int N = ;

vector<int > a[N];

int f[N] , r[N];

void DFS(int u , int dep)//从dep层的u节点处罚,先序遍历计算每个节点的层次

{

    r[u] = dep;

    for(vector<int>::iterator it = a[u].begin();it != a[u].end();++it){

        DFS(*it , dep + );

    }

}

int main(){

   int casenum , num , n , i , x , y;

   scanf("%d" , &casenum);

   for(num = ;num < casenum;num++){

     scanf("%d" , &n);

     for(i = ;i < n;i++) a[i].clear();

     memset(f , - , sizeof(f));

     for(i = ;i < n - ;i++){//n个节点的树 , n-1条边

           scanf("%d %d" , &x , &y);//树种的一个边<x , y>,x是父节点,y是子节点;

           x--;y--;

           a[x].push_back(y);

           f[y] = x;

     }

     for(i = ;f[i] >= ;i++);

     DFS(i , );

     scanf("%d %d" , &x , &y);

     x--;y--;

     while(x != y){

        if(r[x] > r[y])  x = f[x];

        else             y = f[y];

     }

     printf("%d\n" , x + );

   }

}

用树结构支持并查集:

在一般的数据结构的教材中,集合与图、树一样,都是群聚类的非线性表,但是集合更加侧重于包含关系而忽略一个集合中各个元素之间的前后件关系。在一些问题中,我们需要将n个元素划分成若干组,每个组视为一个集合,通常需要涉及集合的合并与查找,因此我们称其为并查集。

并查集需要支持如下的操作:

(1)   Make_set(x):加入单个元素x到集合S中。

(2)   Join(x,y),把x、y所在的不同集合进行合并。

(3)   Set_find(x):得到x所在集合S的代表元。

下面我们来讨论并查集的存储结构。理论上来说,并查集有链结构和树结构两种,但是树结构在完成各个操作时的效率更加优良,我们便直接介绍树结构。

我们用一棵树结构表示集合S={s1,s2,s3,…,sn}.由于我们仅仅是用树结构来表示集合,因此这棵树中的边关系,仅仅是体现了合并操作的前后顺序,边关系不同时,所表达的集合是完全等价的。紧接着,由于树结构依然不能直接存储,我们还要想办法将其转化成线性存储结构。我们如何来表征这样一个集合的特征呢?我们选择一个集合的代表元(也就是树结构表示的并查集的根节点),我们定义set[x]表示元素x所在集合的代表元,而如果x是集合S的代表元,则令set[x] = -1(这种表示方法可以理解为并查集 -> 树结构表示 -> 双亲表示法).那么基于这样的定义,我们能够看到,set[x]与 set[y]的相等关系便可以作为两个元素x、y是否在同一集合的指标了。

查找过程:

对于给出的元素x,我们想要找到x所在集合的代表元,也可以说成是x所在树结构的根节点。直接访问set[x]我们发现存在这样一个问题,x的根节点y在某一次合并操作之后合并到了一个更大的集合,原本是根节点的y变成了树结构中的分支节点,因此我们需要沿树结构继续向上找,我们会遇到相同的问题,因此需要设计一个递归机制。同时为了以后访问的方便,我们采用路径压缩的手法,来使得从x出发找到根节点r的路径经过的所有节点i的set[i]都变成r.

int set_find(int p){

if(set[p] < ) return p; //找到根节点/集合代表元

return set[p] = set_find(set[p]);

}

合并过程:

合并过程就显得很简单,假设我们想要合并元素x、y所在集合,我们只需要分别找到x、y所在集合的代表元p , q,使set[p] = q即可,当然yekeyi 交换p、q的位置。即从x、y所在集合的代表元中选择任意一个成为新的集合的代表元。

void join(int x , y){

  p = set_find(p);

  q = set_find(q)

  if(p != q)

  set[q] = p;

}

数据结构编程实验——chapter8-采用树结构的非线性表编程的更多相关文章

  1. 【Unix网络编程】chapter8基本UDP套接字编程

    chapter8基本UDP套接字编程 8.1 概述 典型的UDP客户端/服务端的函数调用 8.2 recvfrom和sendto函数 #include <sys/socket.h> ssi ...

  2. 数据结构编程实验——chapter9-应用二叉树的基本概念编程

    二叉树是树结构中的重要概念,一些特殊的二叉树如满二叉树和完全二叉树由于节点序号的特殊关系,在一些算法中十分常见. 这篇文章将从三个方面介绍有关二叉树的知识点: (1)   普通有序树转化为二叉树. ( ...

  3. 20172301 《Java软件结构与数据结构》实验二报告

    20172301 <Java软件结构与数据结构>实验二报告 课程:<Java软件结构与数据结构> 班级: 1723 姓名: 郭恺 学号:20172301 实验教师:王志强老师 ...

  4. 2017-2018-2 1723《程序设计与数据结构》实验四 & 实验五 & 课程总结 总结

    作业地址 实验四作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1943 提交情况如图: 实验五作业:https://edu ...

  5. 用Python做2048游戏 网易云课堂配套实验课。通过GUI来体验编程的乐趣。

    第1节 认识wxpython 第2节 画几个形状 第3节 再做个计算器 第4节 最后实现个2048游戏 实验1-认识wxpython 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiy ...

  6. 20172328《程序设计与数据结构》实验四 Android程序设计报告

    20172328<程序设计与数据结构>实验四 Android程序设计报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 李馨雨 学号:20172328 实验教师:王志 ...

  7. 20172328《程序设计与数据结构》实验三 敏捷开发与XP实践报告

    20172328<程序设计与数据结构>实验三 敏捷开发与XP实践报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 李馨雨 学号:20172328 实验教师:王志强 ...

  8. 20172310 2017-2018-2 《程序设计与数据结构》实验三报告(敏捷开发与XP实践)

    20172310 2017-2018-2 <程序设计与数据结构>实验三报告(敏捷开发与XP实践) 课程:<程序设计与数据结构> 班级: 1723 姓名: 仇夏 学号:20172 ...

  9. 20172301 《Java软件结构与数据结构》实验三报告

    20172301 <Java软件结构与数据结构>实验三报告 课程:<Java软件结构与数据结构> 班级: 1723 姓名: 郭恺 学号:20172301 实验教师:王志强老师 ...

随机推荐

  1. 结对随即四则运算(带界面Java版)

    //随机四则运算类 public class 随机四则运算 { public static void main(String[] args) { new 界面();//进入随机四则运算的首界面 } } ...

  2. profibus总线和profibus dp的区别

    profibus总线和profibus dp的区别:PROFBUS是一种国际性的开放式的现场总线标准,它既可以用于高速并且对于时间苛求的数据传输,也可以用于大范围的复杂通讯场合.PROFBUS-DP是 ...

  3. TCP源码—epoll源码及测试

    一.epoll_create & epoll_create1 SYSCALL_DEFINE1(epoll_create, int, size) sys_epoll_create->sys ...

  4. MongoDB中的数据导出为excel CSV 文件

    1.打开命令行,进入我们所安装的mongodb路径下的bin文件夹 2.我们采用bin文件夹下的mongoexport方法进行导出, mongoexport -d myDB -c user -f _i ...

  5. Beta阶段团队项目开发篇章1

    例会时间:2016.12.1 例会照片: 个人工作: 任务分配: 组员 任务内容 李文涛 编写并发布调查问卷 姬索肇 审核并传播调查问卷 韩慧敏 审核并传播调查问卷 任务截止时间 2016.12.4 ...

  6. 【第十周】四则运算GUI

    下载地址:http://pan.baidu.com/s/1hsc9HRm 这次比上次多了一个记录的功能,是用QT里面的qplaintextedit记录显示出做过的题目. 我是直接看的文档,发现窗体,搜 ...

  7. Json的JsonValueProcessor方法

    将对象转换成字符串,是非常常用的功能,尤其在WEB应用中,使用 JSON lib 能够便捷地完成这项工作. JSON lib能够将Java对象转成json格式的字符串,也可以将Java对象转换成xml ...

  8. (转)web性能优化

    前端是庞大的,包括 HTML. CSS. Javascript.Image .Flash等等各种各样的资源.前端优化是复杂的,针对方方面面的资源都有不同的方式.那么,前端优化的目的是什么 ? 1. 从 ...

  9. 使用Fiddler重定向App的网络请求

    前言 开发中手机app只能访问生产环境地址,所以给开发调试带来不便,可以通过Fiddler的代理和urlreplace方式解决. 步骤 1.开启Fiddler的代理模式Tools->Teleri ...

  10. Java并发编程之线程创建和启动(Thread、Runnable、Callable和Future)

    这一系列的文章暂不涉及Java多线程开发中的底层原理以及JMM.JVM部分的解析(将另文总结),主要关注实际编码中Java并发编程的核心知识点和应知应会部分. 说在前面,Java并发编程的实质,是线程 ...