由于在考研的算法题中,栈/队列一般都是通过在函数中设立数组完成(顺序,链式一般不用),所以以后的栈/队列都在用数组操作完成。
层序遍历
层序遍历需要借助队列,根先入队,然后每次出队一个结点,若其有左/右结点,就将其左/右结点入队。这样出队的顺序就是按照从上到下,从左到右的层序遍历顺序。
void LevelOrder3(BiTree T) {
BiTree Q[100]; //假设足够大
int front = 0, rear = 0;
BiNode* p;
Q[rear++] = T; //根先入队
while (front != rear) {
p = Q[front++]; //出队
cout << p->data;
if (p->lchild)
Q[rear++] = p->lchild; //左子入队
if (p->rchild)
Q[rear++] = p->rchild; //右子入队
}
}
1.树高——递归、层序、后序
层序求法:
设立遍历level=0
,last=1
,分别记录层数和左右边结点编号,根为1.
初始时front=rear=0
每当front==last
时,说明已经有一层出队了(队内保存的是下一层的所有结点),此时level++
,并且更新last=rear
,再去出队下一层。
int Depth(BiTree T) {
BiTree Q[100];
int front = 0, rear = 0;
int level = 0, last = 1; //因为每出一层,level++,所以初始level=0
Q[rear++] = T; //根入队
BiNode* p;
while (front != rear) {
p = Q[front++];
if (p->lchild)
Q[rear++] = p->lchild;
if (p->rchild)
Q[rear++] = p->rchild;
if (front == last) { //当最右边结点出队,进行操作,此时队内是下一层所有结点
level++;
last = rear;
}
}
return level;
}
2.树宽
依旧设立last=1
,记录每次最右边的结点,设立nums=1
,记录从第二层开始每层结点数最大值,初始值为1
因为每次最右边结点出队时,若front==last
,进行操作,此时队内是下一层结点,所以我们只能从第二层开始计数,第一层其实必然是1。
int Width(BiTree T) {
if (T == NULL)
return 0;
BiTree Q[100]; //队列
int front = 0, rear = 0; //front指向队首,rear指向队尾后一个
int nums = 1, last = 1; //从第二层开始计数,nums初始值为第一层结点数1,last初始值为第一层左右结点编号
Q[rear++] = T; //根进队
BiNode* p;
while (front != rear) {
p = Q[front++];
if (p->lchild)
Q[rear++] = p->lchild;
if (p->rchild)
Q[rear++] = p->rchild;
if (front == last) { //每出队完了一层结点(出队的p是最右边的结点),那么来计数队内结点数(从第二层开始)
nums = nums > rear - front ? nums : rear - front;
last = rear; //更新last
}
}
return nums;
}
3.判断是否为完全二叉树
我们每次入队时,若p!=NULL
,直接让左右子树都入队。
- 如果是完全二叉树,那么队内必然没有
NULL
,或者NULL
是最后一个进队的叶子(也是出队的)。 - 如果是非完全二叉树,则必然在最后一个元素之前会有
NULL
进队,然后出队。
我们只需要判断,如果有NULL
出队,其如果不是最后一个元素(即其后队内还有其他元素),那么就是非完全二叉树。
bool Q7(BiTree T) {
BiTree Q[100];
int front = 0, rear = 0;
Q[rear++] = T;
BiNode* p;
while (front != rear) {
p = Q[front++];
if (p) {
Q[rear++] = p->lchild; //左右子不判断,直接入队
Q[rear++] = p->rchild;
}
else {
while (front != rear) { //若队内有空,且不是最后一个,即非完全
p = Q[front++];
if (p)
return 0;
}
}
}
return 1;
}