Note: (完整代码放到文章最后)文中涉及到栈的相关代码我会放到最后,实现的为链栈,实现了基本的初始化,入栈,出栈,判空,读取栈顶元素的操作。顺序栈的实现请移步数据结构(线性表篇)------顺序栈 实现:栈的初始化,判空,出、入栈,读取栈顶元素,有关单链表的更多操作请移步数据结构(线性表篇)-----单链表 实现:单链表的初始化(头插法,尾插法),根据序号、值查找结点,插入节点,删除结点
树的结构体定义:
typedef struct _bTNode {
int value;
struct _bTNode* left;
struct _bTNode* right;
} BTNode;
从递归与非递归的角度看,递归方式遍历是最为简单的。只需按照三种遍历方式左中右的先后顺序编写代码即可。虽然代码很简单但这种思想可以用到别的情形中:比如我代码中实现的先序遍历建立树,就是在递归先序遍历的基础上,将访问结点的部分改为malloc新结点。递归方式的三种遍历以及先序遍历建立二叉树的代码如下。
void PreOrder(BTNode* t) {
//先序遍历
if(t != NULL) {
printf("%d ",t->value);
PreOrder(t->left);
PreOrder(t->right);
}
}
void InOrder(BTNode* t) {
//中序遍历
if(t != NULL) {
InOrder(t->left);
printf("%d ",t->value);
InOrder(t->right);
}
}
void PostOrder(BTNode* t) {
//后序遍历
if(t != NULL) {
PostOrder(t->left);//若有左孩子一直向左下走
PostOrder(t->right);//左孩子为空,找右孩子
printf("%d ",t->value);
}
}
//下标如果只是传入一个值,在递归过程中对i修改只限于那一次递归中,所以要传下标的指针。
BTNode* CreatBTree(int arr[],int *i) {
//按给定的数组先序遍历的方式建立二叉树
if(arr[*i] == -1)//约定-1表示空结点
return NULL;
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
node->value = arr[*i];
(*i)++;//注意是(*i),目的是数组下标自增一
node->left = CreatBTree(arr,i);
(*i)++;
node->right = CreatBTree(arr,i);
return node;
}
非递归的遍历方式中,先序遍历与中序遍历基本相同,都是一直找左孩子,并把结点入栈,待访问到空结点就从栈中弹出元素继续访问。不同的是先序遍历在入栈前就访问结点,即每到达一个新结点都会输出该结点值;但中序遍历是在找到最左下方结点后再输出结点值,之后再找右孩子。两者代码中不同的地方就是访问代码的位置。非递归的先序、中序遍历如下。
void _PreOrder(BTNode* t) {
//先序遍历
SNode* s = InitStack();//初始化栈
BTNode* p = t;
while(p || !