二叉树的存储结构
- 顺序存储结构
就是用一维数组来存储二叉树的节点,并且节点存储位置就是数组下标能体系节点之间的逻辑关系。
顺序存储结构一般只用于完全二叉树。对于一般的二叉树,尽管层序编号不能反映逻辑关系,也可以将其按完全二叉树编号,将不存在的节点位置留空。
但是(嗯,凡事都有个但是),考虑下极端情况:一棵深度为k的右斜树,只有k个节点,却要分2^(k-1)个存储单元(可能想上天!)。这种空间浪费的毫无意义!
- 链式存储结构
二叉树每个节点最多有俩孩子。so,脑子里首先蹦出来的就是一个数据域,俩指针域。这样的链表叫做二叉链表。
在含有n个节点的二叉链表中有n+1个空链域
一个节点是有两个链域的,那么n个节点必然有2n个链域,有n-1个分支数(每个分支都是一个链域,描述的就是两个节点之间的关系),叶子节点两个链域都是空的。so,空的链域 = 所有的链域 - 不空的链域。即,2n - (n-1) = n+1
接上代码
节点定义: typedef char TElemType; typedef struct BinTNode{ TElemType data; struct BinTNode *lchild,*rchild; }BinTNode, *BinTree;
遍历二叉树
先序遍历(先根)
中序遍历(中根)
后序遍历(后根)
层序遍历(从上而下,从左置右)
没啥好说的,不懂的出门右拐找百度,左拐也行,你开心随你。
翠花,上酸菜。呃错了,上算法实现:
// 先序遍历二叉树
void preOrderTraverse(BinTree t){
if(t == NULL){
return NULL;
}
printf("%c",t->data);
preOrderTraverse(t->lchild);
preOrderTraverse(t->rchild);
}
// 中序遍历二叉树
void inOrderTraverse(BinTree t){
if(t == NULL){
return NULL;
}
inOrderTraverse(t->lchild);
printf("%c",t->data);
inOrderTraverse(t->rchild);
}
// 后序遍历二叉树
void postOrderTraverse(BinTree t){
if(t == NULL){
return NULL;
}
postOrderTraverse(t->lchild);
postOrderTraverse(t->rchild);
printf("%c",t->data);
}
// 层序遍历二叉树,用到了队列来辅助实现
void levelOrderTraverse(BinTree T) {
LinkQueue *q;
BinTNode *p = T;
if((*p).data != '\0') {
q = LinkQueueInit();
EnQueue(q,*p);
printf("\n");
while(!QueueEmpty(q)) {
BinTNode temp;
DeQueue(q,&temp);
// 简单的访问这个节点,将data输出
printf("%c ",temp.data);
if(temp.lchild != NULL) {
EnQueue(q,*(temp.lchild));
}
if(temp.rchild) {
EnQueue(q, *(temp.rchild));
}
free(&temp);
}
}
}
非递归实现:
// 中序遍历,使用了栈来辅助实现
void inOrderTraverse(BinTree t){
LinkStack *ls = InitStack();
BinTNode *p = t,*temp;
while(p || !StatckEmpty(ls)){
if(p){
Push(ls,*p);
// 入栈后将指针指向节点的左孩子
p = p->lchild;
} else{
temp = Pop(ls);
if(temp){
// 访问节点,我就简单的打印输出。
printf("%c ",temp->data);
p = temp->rchild;
// 将栈中弹出的节点释放掉。
free(temp);
}
}
}
}
// 另一种实现方式
void inOrderTraverse(BinTree b) {
BinTNode *stack[MAXSIZE], *p;
int top = -1;
if (b != NULL) {
p = b;
while (top > -1 || p != NULL) {
// 扫描p的所有左节点并入栈
while (p != NULL) {
top++;
stack[top] = p;
p = p->lchild;
}
if (top > -1) {
// 出栈并访问该节点
p = stack[top];
top--;
printf("%c ", p->data);
// 扫描p的右孩子
p = p->rchild;
}
}
}
}
辅助队列:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "linkqueue.h"
// 队列是否为空
bool QueueEmpty(LinkQueue *lq){
if (lq->front == NULL){
return true;
}
return false;
}
// 初始化一个不带头节点链队列
LinkQueue* LinkQueueInit(){
LinkQueue *lq;
lq = (LinkQueue*)malloc(sizeof(QNode));
lq->front = NULL;
lq->rear = NULL;
return lq;
}
// 入队列,就是单链表的尾插法,rear就是尾指针
Status EnQueue(LinkQueue *lq,BinTNode e){
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
if(!p){
return ERROR;
}
p->data = e;
p->next = NULL;
// 判断是否是一个空的队列,若是空的队列,将队头和队尾指向同一节点
if(lq->front == NULL){
lq->front = lq->rear = p;
} else {
lq->rear->next = p;
lq->rear = p;
}
return OK;
}
// 出队列,从队头出,不就和出栈是一样的吗
Status DeQueue(LinkQueue *lq,BinTNode *v){
QueuePtr *temp;
// 当队头指向NULL,才说明这个队列是个空队列
if(QueueEmpty(lq)){
return ERROR;
}
// 当队列的队头和队尾都指向同一元素节点的时候,将这个节点出队后,把队头和队尾都置为空
*v = lq->front->data;
temp = lq->front;
if(lq->front == lq->rear){
// QueueEmpty仅仅只是判断队头和队尾是否指向同一元素节点,
// 因为队列有一个元素的时候,队头和队尾也是指向同一元素。
lq->rear = lq->front = NULL;
} else {
lq->front = lq->front->next;
}
// 将零食变量所指向的内存单元释放。
free(temp);
return OK;
}
辅助栈:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "linkstack.h"
// 当前栈是否为空栈,栈内元素数量大于0,则返回false
bool StatckEmpty(LinkStack *ls){
return ls->count > 0 ? false : true;
}
// 入栈操作
Status Push(LinkStack *ls,BinTNode v){
LinkStackPtr e = (LinkStackPtr)malloc(sizeof(StockNode));
e->data = v;
// 把当前的栈顶元素值赋值给新节点的直接后继
e->next = ls->top;
// 将新节点赋值给栈顶指针
ls->top = e;
ls->count++;
return OK;
}
// 弹栈
BinTNode *Pop(LinkStack *ls){
if(StatckEmpty(ls)){
return NULL;
}
BinTNode *v = (BinTNode*)malloc(sizeof(BinTNode));
*v = ls->top->data;
// 用来记录要出栈的元素节点
LinkStackPtr temp;
temp = ls->top;
// 使栈顶指针下移,指向后面的节点
ls->top = ls->top->next;
// 释放要出栈元素所在空间
free(temp);
// 将栈的大小更新
ls->count--;
return v;
}
// 获取栈顶元素
void GetTop(LinkStack *ls,BinTNode *v){
if(!StatckEmpty(ls)){
if(!v) {
*v = (BinTNode*)malloc(sizeof(BinTNode));
}
*v = ls->top->data;
}
}
// 获取栈的元素个数
int StatckLength(LinkStack *ls){
if(!StatckEmpty(ls)){
return ls->count;
}
return -1;
}
// 初始化栈
LinkStack* InitStack(){
LinkStack *ls;
ls = (LinkStack *)malloc(sizeof(LinkStack));
ls->top = NULL;
ls->count = 0;
}
main函数:
运行结果:
不足之处,还望指正,蟹蟹!
关于c实现的二叉树非递归方式遍历可以点我,上述代码中的非递归中序遍历另一种实现就是摘自此处。
end