本文主要是介绍树的基本知识总结和上周做的题思路整理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 一、树的一些基本知识
- 1.基本知识
- 2.二叉树
- a.基本知识
- b.特殊二叉树
- c.二叉树的性质
- d.二叉树的遍历
- 二、练习题整理
- 1.智力题 crossing river
- 2.剪花布条(kmp
一、树的一些基本知识
1.基本知识
a)理解:线性结构是一对一的关系,而树是一对多的关系,具有n(n>=0)个结点。
b)结点的分类:
根节点:无前驱的结点,A
叶子结点:或叫终端结点,度为0(有双亲无孩子
GHIJF都是
内部结点:有前驱有后继的结点,BCDE
一个填空题,已知结点数,结点数-1就是分枝儿个数;同样已知分枝儿个数+1就是结点数。可以看做一个结点跟着一个分枝,但根节点无前驱。
2.二叉树
a.基本知识
二叉树定义:二叉树是n(n>=n)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根节点和两棵互不相交的、分别称为根节点的左子树和右子树的二叉树组成。
个人理解:二叉树每个结点最多有两棵子树,也就是度取0,1,2,且按顺序分为左子树和右子树。但如果把二叉树和有序树等价我认为是错误的。对于下图两种情况有序树 树1=树2,而对于二叉树而言这是两种二叉树。
b.特殊二叉树
1.斜树:每一层都只有一个结点,结点个数和二叉树的深度相同。
2.满二叉树:所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上。
3.完全二叉树:满二叉树一定是完全二叉树,二叉树按层序编号,先左子树后右子树,有一定的顺序,编号连续无空档。
c.二叉树的性质
性质1:在二叉树的第i层上至多有2^(i-1)个结点(i>=1)
性质2:深度为k的二叉树至多有2^k-1个结点(k>=1)
性质3:终端结点数为n0,度为2的结点数n2,则n0=n2+1;
联立 n=n0+n1+n2;和n-1=n1+2*n2;
性质3:深度为k的,有n个节点的完全二叉树,当且仅当没一个节点都与深度为k的满二叉树中编号从1至n的节点 一一对应。最后一层:叶子节点尽力靠左。具有n个节点的完全二叉树的深度必为(log2 n)+1。
d.二叉树的遍历
1.前序遍历:先访问根节点,然后前序遍历左子树,再前序遍历右子树。若为空则空操作返回。
简单理解就是先访问父结点,顺序是父节点→长子→次子
偷来大话数据结构的图来理解
悟一下,都是先父后长子次子,也是有迭代套娃的意思。
中序遍历:先访问长子,再访问父结点,再次子
3.后序遍历: 长子→次子→父结点
前中后序的命名是根据父结点放在什么时候遍历而命名的。
4.层序遍历:从根节点开始一层一层,也是先左娃后右娃跑。
二、练习题整理
1.智力题 crossing river
虽然这个题再看是挺简单的,但…总之是蛮改善我码代码的逻辑和思路的…贴上来(以及明白血压升高和松口气的感受 绿色永远滴神!!) 不谝了,贴题贴代码
题目简述:题目大致意思就是有一群人要过河,只有一艘船,一艘船只能乘两个人,每个人过河有各自的过河时间,如果两个人一起过河那么用时按时间长的那个人算,然后求这群人都成功过河用的最短过河时间。(注意还得有人把船划回来
input:The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. The first line of each case contains N, and the second line contains N integers giving the time for each people to cross the river. Each case is preceded by a blank line. There won’t be more than 1000 people and nobody takes more than 100 seconds to cross.(突然懒惰output:For each test case, print a line containing the total number of seconds required for all the N people to cross the river.
Sample Input
1
4
1 2 5 10
Sample Output
17
思路是首先可以想到最小的那个一直做船夫运送人,这显然是一种方法。但假设是1 4 5 6,则会有更优的解决办法。即让最小的两个人做船夫,然后运送人,两个最胖胖先运走。
但一个方法不会一直用,寻找该问题的最小子问题,这个题中找循环规律,每一次循环会送走两个人,判断比较该循环中法1用时短还是法2用时短,ans+=即可
当然首先要判断n=1,2,3的特殊情况
贴上来源代码:
#include<stdio.h>
int n;
int a[1009];
int bubblesort(int a[]) //用冒泡排序进行排序
{int i,j,temp;for(i=0;i<n-1;i++){for(j=0;j<n-i-1;j++){if(a[j]>a[j+1]){temp=a[j];a[j]=a[j+1];a[j+1]=temp;}}}
}
int main()
{int t;scanf("%d",&t);int j;while(t--) //t组人{scanf("%d",&n);//int a[1009];int i;for(i=0;i<n;i++){scanf("%d",&a[i]);}bubblesort(a); //对时间长短进行排序int time1,time2;//两种方法int ans=0;while(n){ //n-=2直到n<=0为止跳出循环if(n==0) {ans=0;n=0;}else if(n==1) {ans+=a[0];n=0;} else if(n==2){ans+=a[1];n=0;}else if(n==3){ans+=a[0]+a[1]+a[2];n=0;}else{time1=a[n-1]+a[0]+a[n-2]+a[0];time2=a[1]+a[0]+a[n-1]+a[1];if(time1<time2) ans+=time1;else ans+=time2;n-=2; //踢去两个胖胖}}printf("%d\n",ans);//写个换行符}return 0;
}
注意按n分类就一直按n分类orz
另外,可以写
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
或者直接
#include<bits/stdc++.h>
using namespace std;`
然后可以用sort(a,a+n),a是数组名,n是数组长度,智能排序
2.剪花布条(kmp
题目:一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?
input:输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。
output:输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。
Sample Input
abcde a3
aaaaaa aa
#.
Sample Output
0
3
直接上源代码
#include<stdio.h>
#include<string.h>//KMP下标从0开始存储
int getNext(char small[],int next[])
{int t=-1;//模式串(用来指示最长公共前缀 int j=0;//用来指示最长公共后缀 int lensmall;lensmall=strlen(small);next[0]=-1;//规定0号位置为-1(若下标从1开始则规定为0 while(j<lensmall-1)//不超过模式串长度 {if(t==-1 || small[t]==small[j]){//next[j+1]=t+1;++t;++j;next[j]=t;//规定next[j+1]=t+1(这里其实是对t的定义 }else t=next[t];//可以把j指示的模式串看成新的主串 }
}
int KMP(char big[],char small[],int next[]){int i=0;//指示主串,下标从0开始 int j=0;//指示模式串,下标从0开始 int ans=0; int lensmall,lenbig;lensmall=strlen(small);lenbig=strlen(big); //strlen()有学问 while(i<lenbig)//不超过主串长度 {if(j==-1 || big[i]==small[j]){++i;++j;}//逐一匹配 else j=next[j];//应用next数组,可以实现指示主串i不回溯 if(j>lensmall-1) ans++;//输出可以剪出多少个(即匹配成功多少次 }return ans;//记得一定要返回ans,否则答案为0 }
int main()
{int next[10010];char big[1000010];char small[10010];//按照题意开范围,千万别开小了 int a[1010]={0}; //作用在输出上 int ans;int i=0;int j;while(scanf("%s",big)){if(big[0]=='#') break;scanf("%s",small);getNext(small,next);ans=KMP(big,small,next);a[i]=ans;i++;//利用while循环将ans以此放入a数组中 j=i;//记录a数组的长度 }for(i=0;i<j;i++){printf("%d\n",a[i]); }//按照题意循环输出
return 0;}
(这是我写注释最多的一次,以后也要好好写注释XD
写这个代码的时候两个问题点
1是要抓住问题的输入输出格式,好好地去实现,不然代码对也会WA
2.关于strlen的问题
首先看下面两个代码(摘自上述源代码
int lensmall=strlen(small);
if(j>lensmall-1) ans++;
if(j>strlen(small)-1) ans++;
第一个代码正确,第二个会报错
经过百度strlen()知 strlen返回的是无符号整数值,而int 返回的是有符号整数值。源代码中的 j 会有取值-1的情况,而-1 无法直接和strlen()比较,会默认为1处理从而报错。 而第一个代码中的lensmall已经是一个int 型,故不会出现问题。
这篇关于树的基本知识总结和上周做的题思路整理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!