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

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

树是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. 【Coursera】支持向量机

    一.最大间隔分类器 1. 函数间隔:\(γ^{i} = y^{i}(w^{T} x + b)\), 改变w和b的量级,对分类结果不会产生任何影响,但是会改变函数间隔的大小.因此,直接对函数间隔求最大值 ...

  2. 【CSAPP笔记】7. 汇编语言——过程调用

    一个过程调用包括将数据(以参数和返回值的形式)与控制从代码的一部分传递到另一部分.除此之外,在进入时为过程的局部变量分配空间,在退出的时候释放这些空间.数据传递.局部变量的分配和释放通过操纵程序栈来实 ...

  3. typedef struct bit0 : 1

    这句话定义了一个位域,bit0是该位域的域名,而且bit0只占用一个位.位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.为了节省存储空间,并使处理简便,C语言提供了一种 ...

  4. vue 过渡效果

    Vue中提供了`<transition>`和`<transition-group>`来为元素增加过渡动画.文档写的很清楚,但是实际使用起来还是费了一番功夫.这里做一个简单的记录 ...

  5. Apache优化之多路处理模块理解

    前言: 当项目被多人访问时导致访问数度变慢,查了许多资料,了解到Apache的核心模块——MPM(多路处理访问模块).在此对MPM的一些知识点进行整理. MPM_WINNT模块 windows系统使用 ...

  6. soap 简单的例子

    首先确保你的soap模块开启 客户端代码 <?php try { $client = new SoapClient(null, array('location' =>"http: ...

  7. 【Linux】Linux定时任务Crontab命令详解

    linux 系统则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的.另 外, 由于使用者自己也可以设置计划任务,所以, ...

  8. oracle表空间到32G后扩容

    ), ) total_space FROM dba_data_files ORDER BY tablespace_name; /*查看表空间的使用情况*/ select a.a1 表空间名称, tru ...

  9. springmvc+mybatis 根据数据的id删除数据

    1. 数据库表 2. notices.jsp <form action="#" method="post"> <fieldset> &l ...

  10. Qss 样式表的尝试

    QLineEdit{ border:1px solid #137eb6; padding:2px; background-color:#F5F5F5; } QToolTip{ border:1px s ...