栈
栈是一种后入先出(LIFO)的数据结构。可以把栈想象成一个羽毛球桶,只有一个开口,最先放进去的羽毛球会在最里面,而最后放进去的羽毛球会在最外面。当我们拿出羽毛球时会先从最外面开始拿,也就是拿的最后放入的羽毛球。
用栈来完成二叉树的三种遍历
以下练习题均来自于leetcode
二叉树的前序遍历
思路:用数组来替代栈,首先是根节点入栈。从栈里面取出一个元素,用一个指针指向这个元素,只要这个元素不为空,就一直指向这个元素的左节点,路上挨个输出节点的字,碰到右节点不为空的时候就把右节点压入栈里。一直循环到栈里没有元素为止。
int* preorderTraversal(struct TreeNode* root, int* returnSize){
struct TreeNode **TreeStack,*p;
int *val=NULL,index=0,size=0;
TreeStack=calloc(sizeof(struct TreeNode*),101);
TreeStack[index++]=root;//根节点入栈
while(index!=0)
{
p=TreeStack[index-1];
index--;
while(p)
{
size++;
val=realloc(val,sizeof(int)*size);
val[size-1]=p->val;
if(p->right)
{
TreeStack[index++]=p->right;
}
p=p->left;
}
}
free(TreeStack);
*returnSize=size;
return val;
}
二叉树的中序遍历
思路:和上题类似,不同的是进栈顺序,前序遍历中遇到有右节点就进栈。而中序遍历一直进栈左节点,直到左节点为空,再输出该节点的值,然后进栈该节点的右节点。一直循环到栈里没有元素为止。
int* inorderTraversal(struct TreeNode* root, int* returnSize){
struct TreeNode **TreeStack,*p;
int *val=NULL,index=0,size=0;
TreeStack=calloc(sizeof(struct TreeNode*),101);
TreeStack[index++]=root;//根节点入栈
while(index!=0)
{
p=TreeStack[index-1];
while(p)//遍历到左节点空
{
TreeStack[index++]=p->left;
p=p->left;
}
index--;//将空节点删除
if(index==0)break;
size++;
val=realloc(val,sizeof(int)*size);
val[size-1]=TreeStack[index-1]->val;
TreeStack[index-1]=TreeStack[index-1]->right;//将左节点出栈,右节点入栈
}
*returnSize=size;
return val;
}
二叉树的后序遍历
思路:与前面不同的是,后续遍历要先一直走到左叶子节点后(过程中经历的节点都要依次进栈),再指向右叶子节点,如果为空就输出该节点的值并弹出该节点,然后用一个变量记录下该输出的节点。如果不为空,且与上次输出的节点不同就将该右节点进栈。
int* postorderTraversal(struct TreeNode* root, int* returnSize){
int index=0,*val=NULL,size=0;
struct TreeNode *p=NULL,*prev=NULL;
struct TreeNode **TreeStack=calloc(sizeof(struct TreeNode*),101);
if(root==NULL)
{
*returnSize=0;
return NULL;
}
TreeStack[index++]=root;
p=TreeStack[index-1];
while(index!=0)
{
while(p)
{
p=p->left;
if(p==NULL)break;
TreeStack[index++]=p;
}
if(index==0)break;
p=TreeStack[index-1];
p=p->right;
if(p!=NULL&&prev!=p)
{
TreeStack[index++]=p;
continue;
}else
{
size++;
val=realloc(val,sizeof(int)*size);
prev=TreeStack[index-1];
val[size-1]=prev->val;
index--;
p=NULL;
}
}
*returnSize=size;
return val;
}
N叉树的前序遍历
思路:与二叉树类似,不同的是要从最右边的节点往左开始进栈。代码如下:
/**
* Definition for a Node.
* struct Node {
* int val;
* int numChildren;
* struct Node** children;
* };
*/
/**********定义一个栈结构,实现进栈出栈的方法************/
typedef struct{
struct Node **tree;
int size;
//int index;
}NodeStack;
NodeStack* NodeStackCreat(void)
{
NodeStack *p;
p=calloc(sizeof(NodeStack),1);
//p->index=0;
p->size=0;
p->tree=NULL;
return p;
}
int NodeStackPush(NodeStack *obj,struct Node *node)
{
obj->size++;
obj->tree=realloc(obj->tree,sizeof(struct Node*)*obj->size);
if(obj->tree==NULL)return -1;
obj->tree[obj->size-1]=node;
return 0;
}
struct Node* NodeStackPop(NodeStack *obj)
{
if(obj->size==0)
{
return NULL;
}
obj->size--;
struct Node* p=obj->tree[obj->size];
obj->tree=realloc(obj->tree,sizeof(struct Node*)*obj->size);
return p;
}
bool NodeStackIsEmpty(NodeStack *obj)
{
if(obj->size==0)return true;
return false;
}
/**********定义一个栈结构,实现进栈出栈的方法************/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* preorder(struct Node* root, int* returnSize) {
int size=0,*val=NULL;
struct Node *res;
NodeStack *MyStack=NodeStackCreat();
//根节点入栈
NodeStackPush(MyStack, root);
while(!NodeStackIsEmpty(MyStack))
{
res=NodeStackPop(MyStack);
if(res==NULL)break;
while(res)
{
size++;
val=realloc(val,sizeof(int)*size);
val[size-1]=res->val;
//printf("%d,",res->val);
if(res->numChildren>0)
{
for(int i=res->numChildren;i>0;i--)
{
NodeStackPush(MyStack,res->children[i-1]);
}
break;
}else break;
}
}
*returnSize=size;
return val;
}
N 叉树的后序遍历
思路:这里与二叉树的后序思路不同(因为想了好久也没想出来对应着二叉树的模板写),想了种取巧的方法,就是用前序求解,只不过是从左往右一次入栈。到最后输出结果时做一次反转,比如上图中从右往左看,从上往下看的顺序依次是:1,4,2,3,6,5;刚好是后序的反转。
代码如下:
/**
* Definition for a Node.
* struct Node {
* int val;
* int numChildren;
* struct Node** children;
* };
*/
typedef struct{
struct Node **tree;
int size;
//int index;
}NodeStack;
NodeStack* NodeStackCreat(void)
{
NodeStack *p;
p=calloc(sizeof(NodeStack),1);
//p->index=0;
p->size=0;
p->tree=NULL;
return p;
}
int NodeStackPush(NodeStack *obj,struct Node *node)
{
obj->size++;
obj->tree=realloc(obj->tree,sizeof(struct Node*)*obj->size);
if(obj->tree==NULL)return -1;
obj->tree[obj->size-1]=node;
return 0;
}
struct Node* NodeStackPop(NodeStack *obj)
{
if(obj->size==0)
{
return NULL;
}
obj->size--;
struct Node* p=obj->tree[obj->size];
obj->tree=realloc(obj->tree,sizeof(struct Node*)*obj->size);
return p;
}
bool NodeStackIsEmpty(NodeStack *obj)
{
if(obj->size==0)return true;
return false;
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* postorder(struct Node* root, int* returnSize) {
int size=0,*val=NULL;
struct Node *res;
NodeStack *MyStack=NodeStackCreat();
//根节点入栈
NodeStackPush(MyStack, root);
while(!NodeStackIsEmpty(MyStack))
{
res=NodeStackPop(MyStack);
if(res==NULL)break;
while(res)
{
size++;
val=realloc(val,sizeof(int)*size);
val[size-1]=res->val;
//printf("%d,",res->val);
if(res->numChildren>0)
{
for(int i=0;i<res->numChildren;i++)
{
NodeStackPush(MyStack,res->children[i]);
}
break;
}else break;
}
}
for(int i=0,j=size-1;i<j;i++,j--)
{
int temp=val[i];
val[i]=val[j];
val[j]=temp;
}
*returnSize=size;
return val;
}