二叉树基础知识:
1.栈、队列和顺序表都是线性结构
但是二叉树不是,二叉树是多分支结构
2.任何一棵树都可以拆分为子树和根节点,许多二叉树的相关问题都是用分治的思想进行函数的递归进行解决。
例:前序,中序,后序遍历二叉树
前序遍历:
void print_Front(pNode a)
{
if (a == NULL)
{
printf("N ");
return;
}
printf("%d ", a->val);
print_Front(a->LeftChild);
print_Front(a->RightChild);
}
3.二叉树链表实现可以用左孩子、右兄弟的方法来找到各个节点
struct TreeNode
{
int data;
struct TreeNode* leftchild;
struct TreeNode* rightbrother;
};
图:
如上图,就可以找到二叉树中的所有节点。但缺点是:空间存在不小的浪费。
4.也可以用双亲表示法来用数组造二叉树(但是:该方法只适合满二叉树和完全二叉树):
即:每个元素都存储好自己的父亲的下标位置,没有父亲的存-1
下标位置规律:
左孩子下标 = 父下标 * 2 + 1
右孩子下标 = 父下标 * 2 + 2
父下标 = (孩子下标 - 1 ) / 2
例:
注:物理结构是数组(实际上的)
逻辑结构是二叉树(想象中的)
4.5.搜索二叉树特点:
左节点数据 < 根数据 < 右节点数据
5.堆:
堆分为大堆和小堆,但他们都是完全二叉树
大堆:父节点都大于子节点
小堆:父节点都小于子节点
6.完全二叉树要用数组去存储,但非完全二叉树要用链式结构去存储:
可以用二叉链和三叉链存储
二叉链:
三叉链:
做题时要具备的良好素养:
1.一个节点含有的子树的个数就是该节点的度
2.一棵具有n个节点的树有n-1条边
3.子树不能相交,即树不能有环
4.度为二的节点的个数始终等于度为零的节点个数 - 1
即:n0 = n2 + 1
5.二叉树可以是空树
6.完全二叉树的节点N和高度h的关系:
完全二叉树为满二叉树的情况:
N = 2 ^ h - 1
h = log(N + 1)
完全二叉树最后一层只有一个节点的情况:
N = 2 ^ (h - 1)
h = logN + 1
建议先记N = f(h),指数形式的这个好记
7.堆插入数据:用的是向上调整算法,时间复杂度:O(logN)
插入数据:
直接在数组尾部插入数据,然后向上调整
堆删除数据:用的是向下调整算法,时间复杂度:O(logN)
删除操作:
将顶部数据和数组最后一个元素换位,然后数组元素总数--,再让顶部数据向下调整
8.想要用向上调整建堆或向下调整建堆,就必须先确保根节点的左子树和右子树都统一是大堆或小堆,然后才能用此方法
9.用堆排序来排列一个升序数组:
用到了向下调整算法,向下调整建堆
typedef int tree_data_type;
void Swap(int* p1, int* p2)
{
int tem = *p1;
*p1 = *p2;
*p2 = tem;
}
void Downsort_alg(int *a, int father, int n)
{
int flag = 1;
while (flag == 1)
{
flag = 0;
if (father * 2 + 1 >= n)
{
break;
}
tree_data_type tem = father * 2 + 1;
if (father * 2 + 2 < n && a[father * 2 + 1] < a[father * 2 + 2])
{
tem = father * 2 + 2;
}
if (a[tem] > a[father])
{
Swap(&a[tem], &a[father]);
flag = 1;
father = tem;
}
}
}
void Heapsort(int* a, int n)
{
assert(a);
assert(n > 0);
int i = (n - 1 - 1) / 2;
for (; i >= 0; i--)
{
Downsort_alg(a, i, n);
}
}
void Heap_sort_order(int* a, int n)
{
assert(a);
assert(n > 0);
Heapsort(a, n);
int i = 0;
while(n > 0)
{
Swap(&a[0], &a[n - 1]);
--n;
Downsort_alg(a, 0, n);
}
}
10.想要在n个数据中选出前k大的数据:
建一个可以容纳k个元素的小堆
遍历n个数据,只要某个数据比顶点数据大,就将二者置换,接着向下调整算法。
完事后,堆里边的就是前k大的数据
时间复杂度:k + (N - k) * logk
这是N远大于k的情况下
例:
在n个数据里边找前k小的数据
void create()
{
srand((unsigned int)time(NULL));
FILE* pf = fopen("test.txt", "w");
int i = 0;
for (i = 0; i < 10000; i++)
{
int tem = rand() * 100 + rand() * 10 + rand();
fprintf(pf, "%d\n", tem);
}
fclose(pf);
pf = NULL;
}
#define k 5
void Top(int n)
{
FILE* pf = fopen("test.txt", "r");
int a[k];
int i = 0;
for (; i < k; i++)
{
fscanf(pf, "%d", &a[i]);
}
Heapsort(a, k);//建的是大堆
//找前k小的值
for (; i < n; i++)
{
int tem;
fscanf(pf, "%d", &tem);
if (tem < a[0])
{
int tem1 = tem;
tem = a[0];
a[0] = tem1;
Heapsort(a, k);
}
}
print(a, k);
fclose(pf);
pf = NULL;
}
11.二叉树的层序遍历:
新造数组来完成,出一个进一个,没孩子不进或进NULL
例:
造数组出来的过程就是
12.OJ题目当中的二叉树用数组表示时,都是用的层序
13.若根节点层数为1,则非空二叉树的第i层上最多2^(i - 1)个节点