一、树的一些基本知识
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 型,故不会出现问题。