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

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

树是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. 第一次spring冲刺第3、4天

    11月14至15日 因为忙于项目的谈论与探究,以及周末的活动变动,使得博客没有时间提交上去,这里补交. 这两天,主要是应对于市场的探究做谈论,我们主要面对什么类型的客户,以及他们最需要的是什么等话题做 ...

  2. 【动态规划】POJ-3616

    一.题目 Description Bessie is such a hard-working cow. In fact, she is so focused on maximizing her pro ...

  3. Objective-C KVC讲解,包你看懂会用

    KVC:Key Value Coding,取其三个单词首字母浓缩而成.直白翻译过来就是键值编码,什么意思呢?简单来说,就是操作一个对象,也可以像操作字典一样,通过key来取值和赋值. 我们先创建一个H ...

  4. 七类网线 支持10gb/s的速度的计算方法

    0. 说明 我是数学白痴, 只是套了下公式... 1. 七类网线的参数: 七类线 ISO/IEC 7类/F级标准 中最新的一种双绞线,它主要为了适应万兆位以太网技术的应用和发展.但它不再是一种非屏蔽双 ...

  5. Window环境下搭建Vue.js开发环境

    原文链接:http://blog.csdn.net/solo95/article/details/72084907 笔者最近在进行前端的学习,在点完了HTML5.CSS3.JavaScript等技能树 ...

  6. validate效验规则

    ] } }, messages:{ name:{ required:"最少为2个字!" }, tel:{ required:"请填写手机号码!", isMobi ...

  7. SGU438_The Glorious Karlutka River =)

    好题,有一些人在河的一边,想通过河里的某些点跳到对岸去.每个点最多只能承受一定数量的人,每人跳跃一次需要消耗一个时间.求所有人都过河的最短时间. 看网上说是用了什么动态流的神奇东东.其实就是最大流吧, ...

  8. 【bzoj4591】[Shoi2015]超能粒子炮·改 Lucas定理

    题目描述 曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加强大的粒子流的神秘装置.超能粒子炮·改相比超能粒子炮,在威力上有了本质的提 ...

  9. P3165 [CQOI2014]排序机械臂

    题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到高度最低的物品的位置 P1P_1P1​ ,并把左起第一个物品至 P1P_1P1 ...

  10. [AT2384] [agc015_f] Kenus the Ancient Greek

    题目链接 AtCoder:https://agc015.contest.atcoder.jp/tasks/agc015_f 洛谷:https://www.luogu.org/problemnew/sh ...