数据结构第五周笔记——树(下3)(慕课浙大版本--XiaoYu)

简介: 小白专场,更详细的讲解,让基础不好也能够看懂

小白专场:堆中的路径-C语言实现

堆中的路径

  1. 网络异常,图片无法展示
    |

  2. 5 3的意思是给你5个数据构成一个最小堆进行3次查询。第二行就是要插入的五个数据。5 4 3代表下标

网络异常,图片无法展示
|

堆的表示及其操作(堆是一种按一定顺序组织的完全二叉树)

#define MAXN 1001

#define MINH -10001

intH[MAXN],size;//由于堆在存储的时候是把根结点放在数组下标为1的地方,也就是说0是空缺的

//这样子按照一层层顺序逐个往数组后面存放,使得堆中的任何一个元素可以很容易的找到他的父节点在哪里,左右儿子在哪里

//整数size表示当前堆大小

voidCreate()//堆的初始化,就是建立一个空堆(size设置为0)

{

   size=0;

   H[0] =MINH;//设置岗哨

}

//插入操作

voidInsert(intX)

{

   //将X插入H。这里省略检查堆是否已满的代码

   inti;

   for(i=++size;H[i/2]>X;i/=2)

       H[i] =H[i/2];//i挪到父节点(i/2)的位置

   H[i] =X;

}

主程序

   intmain()

{

   1.读入n和m

   2.根据输入序列建堆

   3.对m个要求:打印到根的路径

       

       return0;

}

//具体实现程序

intmain()

{

   intn,m,x,i,j;

   

   scanf("%d%d",&n,&m);

   Create();//堆初始化

   for(i=0;i<n; i++ ) {//以逐个插入方式建堆

       scanf("%d",&x);

       Insert(x);//利用Insert函数插到堆中

   }

   //m个查询

   for(i=0;i<m;i++){

       scanf("%d",&j);

       printf("d",H[j]);

       while(j<1){//沿根方向输出各结点(也就是说把他的祖先全部打印出来了)当j>1是代表还没有到根的时候,根的位置是1,这时候j/2就代表了他父节点的位置

           j/=2;

           printf("%d",H[j]);

       }

       printf("\n");

   }

   return0;

}

小白专场[陈越]:File Transfer (是一道经典的并查集的应用题)-C语言实现

小白-FT.1 集合的简化表示

集合的表示方法

typedefstruct {

   ElementTypeData;

   intParent;

}SetType;

查找Find函数

intFind(SetTypeS[],ElementTypeX)

{

   inti;

   for(i=0; i<MaxSize&&S[i].Data!=X; i++);//找到X在集合中是第几个元素,这个时间复杂度是O(N2)这个数量级,可以有更好的方法来寻找

   if( i>=MaxSize ) return-1;

   for(;S[i].Parent>=0;i=S[i].Parent);

   returni;

}

网络异常,图片无法展示
|

但其实这个声明这个Data专门用来存储是可以省略的,直接用数组来存储就行了,想知道有几个独立的集合就看数组里面有几个-1就可以了(-1表示处于最上方的了)

网络异常,图片无法展示
|

集合简化表示

typedefintElementType;//默认元素可以用非负整数表示

typedefintSetNameL;//默认用根结点的下标作为集合名称

typedefElementTypeSetType[MaxSize];

SetNameFind(SetTypeS,ElementTypeX)//这个X直接就是数组的下标

{

   //默认集合元素全部初始化为-1

   for(;S[X]>=0;X=S[X]);//这和S[X]里面存的直接就是X的父节点

   returnX;

}

voidUnion (SetTypeS, SetNameRoot1,SetNameRoot2)

{

   //这里默认Root1和Root2是不同集合的根结点

   S[Root2] =Root1;

}

小白-FT.2 题意理解与TSSN的实现

题意理解

C:检测能不能连通,能就Yes不行就No

I:连通

S:输入结束

网络异常,图片无法展示
|

在这里面每台计算机都是直接或者间接连通的。在上图中1虽然是一个孤立的计算机,但他也被认为是跟自己连通的

所以这个会输出:There are 2 components (这个系统有两个连通机)

网络异常,图片无法展示
|

在上图的这种情况下,输出的最后一行就应该是The network is connected(这个网络是连通的)

程序框架搭建

intmain()

{

   初始化集合;

   do{

       读入一条指令;

       处理指令;

   }while(没结束);

   return0;

}

翻译为具体代码如下

intmain()

{

   SetTypeS;//这是并查集

   intn;//n是集合里面元素的个数

   charin;//第一个字符被命名为in

   

   //初始化集合

   scanf("%d\n",&n);

   Initialization(S,n);

   do{

       scanf("%c",&in);

       switch(in){

           case'I':Input_connection(S);break;//把两台需要连接的计算机的编号读进来,检查是否连接好了,没连接好就连接一下

               //Union和Find函数都会出现在上方那个函数当中

           case'C':Check_connection(s);break;//这个函数要做的就是读入待查询的计算机的编号,检查他们在不在一个集合里面,用到Find函数

           case'S':Check_network(s,n);break;//检查网络是否已经连通了

       }

   }while(in!='S');

   

   

   

   

   return0;

}

网络异常,图片无法展示
|

答案是A

程序框架搭建2

//处理输入

voidInput_connection(SetTypeS)

{

   ElementTypeu,v;

   SetNameRoot1,Root2;

   scanf("%d %d\n",&u,&v);

   Root1=Find(S,u-1);

   Root2=Find(S,v-1);

   if( Root1!=Root2 )

       Union(S,Root1,Root2);

}

-----------------------------------------------------------------

//处理查询

voidCheck_connection(SetTypeS)

{

   ElementTypeu,v;

   SetNameRoot1,Root2;

   scanf("%d %d\n",&u,&v);

   Root1=Find(S,u-1);

   Root2=Find(S,v-1);

   if( Root1==Root2 )

       printf("Yes\n");

   elseprintf("no\n")

}

--------------------------------------------------

//检查整个网络是否已经连通

   voidCheck_network(SetTypeS,intn)

{

   inti,count=0;

   for(i=0; i<n; i++){

       if( S[i] <0 ) counter++//只要S[i] < 0就意味着这是一个根节点

   }

   if(counter==1)//只有一个根节点表示整个集合全部连通了

       printf("The network is connected.\n");//输出网络连通了

   else

       printf("There are %d conponents.\n",counter);//输出一共有剁谁个连通集

}

运行效率取决于Find函数与Union函数怎么实现的

TSSN(to simple sometime neive)实现

小白-FT.3 按秩归并

为什么需要按秩归并?

1. Union(Find(2),Find(1))//注意2在前,1在后。前面输入集合1后面输入集合2。让集合2指向集合1。其实也就是1指向2

2. Union(Find(3),Find(1))//这里1指向3了,由于上面那个,相当于2也指向3了

  1. 网络异常,图片无法展示
    |
    但这样显然会让树越来越高,有几个数,树就有多高,退化成单链表了,而且每次都绑定在1身上就意味着每次都需要从1开始找,直到找到他的根结点刚才一系列Union(Find(), Find(1))(其中)操作的时间复杂度是:T(n) = O(n²)为什么树的高度会越来越高
    网络异常,图片无法展示
    |
  1. 只要把矮树贴到高树上就可以避免这种情况。但这样就势必要判断树的高度再决定谁贴到谁身上
  1. 树的高度存哪里?

S[Root] =-1//这是根结点,设置为-1就不会是任何一个元素的下标了,这样就把他和其他的非根结点区别开了。写-1或者-100都是没有区别的都可以

   //由这个想法向后延伸

   S[Root] =-树高//依旧初始化为-1,这棵树的高度一开始就是1,每个计算机都是单独的一个结点

   //代码演示(伪代码)

   if( Root2高度>Root1高度 )

       S[Root1] =Root2;//集合1指向集合2

   else{

       if(两树一样高) 树高++;//存在新的结点里面

       S[Root2] =Root1;

   }

//实际代码,比高度的做法

   if( S[Root2] <S[Root1] )//因为存的是负数,所以需要反着来

       S[Root1] =Root2;//集合1指向集合2

   else{

       if( S[Root1] ==S[Root2] ) Root1--;//存在新的结点里面,是负数负数负数,需要--而不是++

       S[Root2] =Root1;

   }

  1. 另一种做法:比规模
  1. 把小树贴在大树上
  2. S[Root] = -元素个数
  3. 最后那个结果树的规模都会改变,变为两个树的规模之和

voidUnion(SetTypeS,SetNameRoot1,SetNameRoot2)

{

   if(S[Root2] <S[Root1] ){

       S[Root2] +=S[Root1];

       S[Root1] =Root2;//把集合小的贴到大的上面去,在这里Root2更大,条件中只是因为是负数表示反过来了而已

   }

   else{

       S[Root1] +=S[Root2];

       S[Root2] =Root1;

   }

}

  1. 上述的两种方法都统称按秩归并
    按秩归并:最坏情况下树高 = O(logN)

小白-FT.4 路径压缩

按秩归并是对Union的一个改进

路径压缩是对Find这个函数的一个改进

SetNameFind (SetTypeS,ElementTypeX)

{

   if(S[X] <0 )//找到集合的根,X如果小于0的话那就意味着X本身就已经是根了,直接返回就行了

       returnX;

   else

       returnS[X] =Find( S,S[X]);//先找到根,把根变为X的父结点,再返回根

}

网络异常,图片无法展示
|

网络异常,图片无法展示
|

路径压缩好处:

  1. 第一次调用find会稍微复杂一点,但只要后续还需要调用就会非常合算
  2. Find函数的递归调用是一个伪递归调用(不会像递归一样把堆栈压爆掉,因为是非常容易转换成循环的,编辑器可能直接执行优化过后的循环代码)

网络异常,图片无法展示
|

做不做路径压缩的本质区别:

  1. 在查找次数M前面,到底是要乘一个常数还是要乘一个logN的问题。logN是N的一个递增函数,当N趋向无穷大的时候,logN也会趋向于无穷大。常数是不会变的
  2. 当N充分大的时候


目录
相关文章
|
1月前
|
算法
数据结构之博弈树搜索(深度优先搜索)
本文介绍了使用深度优先搜索(DFS)算法在二叉树中执行遍历及构建链表的过程。首先定义了二叉树节点`TreeNode`和链表节点`ListNode`的结构体。通过递归函数`dfs`实现了二叉树的深度优先遍历,按预序(根、左、右)输出节点值。接着,通过`buildLinkedList`函数根据DFS遍历的顺序构建了一个单链表,展示了如何将树结构转换为线性结构。最后,讨论了此算法的优点,如实现简单和内存效率高,同时也指出了潜在的内存管理问题,并分析了算法的时间复杂度。
54 0
|
29天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
55 5
|
1月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
94 16
|
1月前
|
算法
数据结构之文件系统模拟(树数据结构)
本文介绍了文件系统模拟及其核心概念,包括树状数据结构、节点结构、文件系统类和相关操作。通过构建虚拟环境,模拟文件的创建、删除、移动、搜索等操作,展示了文件系统的基本功能和性能。代码示例演示了这些操作的具体实现,包括文件和目录的创建、移动和删除。文章还讨论了该算法的优势和局限性,如灵活性高但节点移除效率低等问题。
55 0
|
2月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
32 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
2月前
|
Java C++
【数据结构】探索红黑树的奥秘:自平衡原理图解及与二叉查找树的比较
本文深入解析红黑树的自平衡原理,介绍其五大原则,并通过图解和代码示例展示其内部机制。同时,对比红黑树与二叉查找树的性能差异,帮助读者更好地理解这两种数据结构的特点和应用场景。
42 0
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
218 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
37 1
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。