二叉树,最多有两个子节点的树。
满二叉树,除了最后一层的节点,每个节点都有两个子节点的二叉树
完全二叉树,只有最后一层有若干个非二子节点的二叉树。
完全二叉树可以使用编号,1~n,计算规律,第i层有2^(i-1) 个节点, (i从一开始计算), 同时可以看到i作为父节点,其子节点的编号就是2*i和2*i+1,
度数是指一个节点拥有子节点的个数,用a表示度数为0的节点的个数,b对应度数为1的节点的个数,c对应度数为2的节点的个数,可以看到一个神奇的一点,度数为0的节点如果变成了度数为2的子节点(子节点没有自己的子节点了哦),那么a=a-1+2=a+1,b不变,c++, 如果它变成了一个度数为1的节点,那么a=a-1+1=a, b++, c不变, 在这里可以看到一个二叉树是从根节点开始扩展到一个二叉树的大小的,那么这样来推就会发现度数为0的节点数和度数为2的节点数是同时增加减少的,从最开始的比较来看则可以得出a-c=1恒成立。
前序遍历:按照根,左子节点,右子节点的顺序对树中的元素进行遍历。
中序遍历:按照左子节点,根,右子节点的顺序blablabla
后序遍历:按照左子节点,右子节点,根的顺序进行遍历。
可以看到从左到右的顺序是不变的,前中后的区别在于根被遍历的顺序。
这里是针对一个小的树的结构对应的遍历顺序,放到由小树构成的大树中就是对每一个父亲节点都做这样的顺序判断,然后进行到下一个父节点,类似递归,直到度数为0再回溯。
计数排序:我们要进行对一个整数的数组进行排序,(比如一个每个数字范围在0~100的数组),我们就开一个长度为101的数组arr,这个数组的内部用零初始化,然后扫描一遍数组,碰到一个数字i,就把arr[i]的内容加一,在扫描完成之后可以看到这个arr数组的第i个就是代表了之前扫描的数组的含有i的个数,这样我们就从统计学意义上将一个数组有序离散化,我们可以创造一个前缀和数组sum,(用arr得到),这个数组sum的第i个就是所有的数字一直到i(包括i)的数目,可以看到sum[i-1]就是i的对应的名次。用空间换时间,这样的排序很快。这个就是简化版的桶排序,我们可以把一个大的数据序列根据其值域的不同(没有重合部分的值域)放到若干个桶中,每个桶对应了自己的上界和下界,然后把满足对应范围的数据放入这个桶里,最后如果我们想要在统计意义上的排序,其实就已经离散化地完成了,进一步就是对每一个桶里的数据进行排序了。这个思想是分治的思想,即是将一个大问题分成无数小问题,对小问题求解后再合成大的问题。
基数排序:在同排序的基础上进行的,因为如果我们要排序的数字太大了,那么就可以使用分别对不同的数位进行分配,比如对一个不超过三位数的整数构成的序列排序,那么可以定义三个数组,分别用来存个位十位百位,然后再扫描的过程中对应的数字放到数组对应的位置,在排序中就按照对应数位的顺序进行查找即可了。数组的元素就是要被排序的数组的元素。
归并排序,也是一种分治的思想,不断对数组进行二分,分成的小数组再进行归并排序(没错就是递归)直到最后分成一个元素形成的数组开始回溯,这里回溯的时候要写一个能将两个有序数组合并成一个有序数组的函数merge,这是归并排序的精髓,参见leetcode中合并有序链表那道题的思想,用两个指针进行操作。
快速排序,每次随机选择一个数字mid然后扫描一遍数组,被扫到的数字如果大于mid就放在数组的右边,小于mid就放在左边,这样不断放,放在mid左右的大小关系是确定的,然后就只需要对左右两个小的数组进行排序,继续类似快速排序的放在两边的方法,直到只有一个元素的时候返回。