二叉树的详细解读

二叉树的概念

  • 一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵分别称为左子树和右子树的二叉树组成
  • 二叉树的特点:每个结点最多有两棵子树,即二叉树不存在度大于2的结点
  • 二叉树的子树有左右之分,其子树的次序不能颠倒
  • 因此:二叉树是通过上述5中形式的组合或嵌套而形成

满二叉树&完全二叉树

  • 满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子节点都在同一层上
  • 完全二叉树:如果一棵具有N个结点的二叉树的结构与满二叉树的前N个结点的结构相同,称为完全二叉树

二叉树性质

  • 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 2^(i-1) (i>0)个结点
  • 若规定只有根节点的二叉树的深度为1,则深度为K的二叉树的最大结点数是(2^k)-1 (k>=0)
  • 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数 为 n2,则有n0=n2+1
  • 具有n个结点的完全二叉树的深度k为 Log2(n+1) 上取整
  • 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序 对所有节点从0开始编号,则对于序号为i的结点有:
    • 若i>0,双亲序号:(i-1)/2;
      i=0,i为根节点编号,无双亲结点
    • 若2i+1<n,左孩子序号:2i+1,否则无左孩子
    • 若2i+2<n,右孩子序号:2i+2,否则无右孩子

二叉树存储结构

  • 二叉树主要有顺序存储链式存储结构
  • 顺序存储结构 对于一棵完全二叉树所有结点按照层序自顶向下,同一层自左向右顺 序编号,就得到一个节点的顺序序列


  • 优点:存储完全二叉树,简单省空间
  • 缺点:存储一般二叉树尤其单支树,存储空间利用不高
    链式存储

二叉树的基本操作

  • 二叉树的遍历

  • 遵循某种次序,遍历二叉树中的所有节点,使得每个结点被访问一 次,而且仅访问一次。“访问”:即对结点施行某些操作。
    若规定VLR分别代表:遍历根节点、遍历根节点的左子树、遍历根节 点的右子树,

  • 则有:

  • 前序:VLR

  • 中序:LVR

  • 后序:LRV

  • 二叉树层序遍历

  • 按照二叉树的层序次序(即从根节点层到叶结点层),同一层中按先左 子树再右子树的次序遍历二叉树

  • 因此:在所有未被访问结点的集合中,排列在已访问结点集合中最前 面结点的左子树的根节点将最先被访问,然后是该结点的右子树的根 节点。

  • 二叉树的其他操作

  • 求二叉树的高度

  • 求二叉树叶子结点的个数

  • 求二叉树结点的个数

  • 求二叉树第K层结点的个数

  • 判断一个节点是否在一棵二叉树中

  • 获取一个节点的双亲结点

  • 获取一个节点的左孩子结点

  • 获取一个节点的右孩子结点

  • 将三种递归遍历方式转换为非递归形式

  • 求二叉树的镜像(递归&非递归)

  • 判断一棵二叉树是否为完全二叉树(层序遍历变形)

  • 创建二叉树

  • 前/中/后遍历二叉树(递归&非递归)

  • 层序遍历二叉树

  • 求二叉树中两个结点的最近公共祖先结点

  • 判断一棵二叉树是否是平衡二叉树

  • 求二叉树中最远的两个结点之间的距离

  • 有前序遍历和中序遍历重建二叉树(前序遍历结果:1,2,3,4,5,6 中序 遍历结果:4,2,5,1,6,3)

  • 判断一棵二叉树是否是完全二叉树

  • 求二叉树的镜像

好了,到了看代码的时间了

  • 先来看看我定义的结构体
typedef char DataType;typedef struct BTNode
{DataType _data; //数据struct BTNode* _pLeft;  //左子树struct BTNode* _pRight;  //右子树
}BTNode;
  • 创建二叉树,我是利用递归创建的,用的先序遍历的思想。即先创建根节点,然后创建左子树,后创建右子树。
BTNode* BuyBTNode(DataType data)
{BTNode* temp = (BTNode*)malloc(sizeof(BTNode));if (!temp){assert(0);return;}temp->_data = data;temp->_pLeft = NULL;temp->_pRight = NULL;
}//str 存放元素的数组,size 元素个数,index 递归到第几个个元素,invalid 树中空位置
void CreateBinTree(BTNode** pRoot, char* str, int size, int* index, DataType invalid)
{assert(pRoot);assert(index);if (*index < size && str[*index] != invalid){*pRoot = BuyBTNode(str[*index]);//创建根节点++(*index);CreateBinTree(&((*pRoot)->_pLeft), str, size, index, invalid);//创建左节点++(*index);CreateBinTree(&((*pRoot)->_pRight), str, size, index, invalid);//创建右节点}
}
  • 先序遍历(递归),递归代码比较简单,我就不罗嗦了。
void PreOrder(BTNode* pRoot)
{if (pRoot == NULL)return;printf("%c ", pRoot->_data);PreOrder(pRoot->_pLeft);PreOrder(pRoot->_pRight);
}
  • 先序遍历(非递归):这里用到栈的数据结构。先将根节点入栈,然后进入循环,判断条件是栈是否为空;在循环中,我们先取到栈顶元素,打印完之后出栈,接下来,我们将这个节点的左右子树入栈,如果为空,则不入。这里顺序必须先是右子树,再是左子树;因为栈具有后进先出的性质。然后让他循环就好了。
void PreOrderNor(BTNode* pRoot)
{assert(pRoot);Stack s;BTNode* temp = NULL;InitStack(&s);PushStack(&s, pRoot);while (!EmptyStack(&s)){temp = TopStack(&s);PopStack(&s);printf("%c ", temp->_data);if (temp->_pRight)PushStack(&s, temp->_pRight);if (temp->_pLeft)PushStack(&s, temp->_pLeft);}
}
  • 中序遍历(递归)
void InOrder(BTNode* pRoot)
{if (pRoot == NULL)return;InOrder(pRoot->_pLeft);printf("%c ", pRoot->_data);InOrder(pRoot->_pRight);
}
  • 中序遍历(非递归):开始初始化时将我的temp设置为pRoot根节点,进入循环,条件是temp不为空或者栈不为空;循环里面,我们先将temp中所有左子树入栈,接下来打印temp的元素,并且出栈,最后让temp指向他的右子树就好了。继续让他循环就好了。
void InOrderNor(BTNode* pRoot)
{assert(pRoot);Stack s;BTNode* temp = pRoot;InitStack(&s);while (temp != NULL || !EmptyStack(&s)){        while (temp){PushStack(&s, temp);temp = temp->_pLeft;}temp = TopStack(&s);printf("%c ", temp->_data);PopStack(&s);temp = temp->_pRight;}
}
  • 后序遍历(递归)

void PostOrder(BTNode* pRoot)
{if (pRoot == NULL)return;PostOrder(pRoot->_pLeft);PostOrder(pRoot->_pRight);printf("%c ", pRoot->_data);
}
  • 后序遍历(非递归):先初始化一个栈,将根节点入栈,然后进入循环,循环条件是栈不为空;循环里面一个判断条件是栈顶元素是叶子节点或者叶子节点的根节点,那么我们就打印并且出栈。最后将此元素的左右孩子入栈,还有有顺序的,必须是先右孩子,然后才能入左孩子。
void PostOrderNor(BTNode* pRoot)
{assert(pRoot);BTNode* cur = NULL;BTNode* prev = NULL;Stack s;InitStack(&s);PushStack(&s, pRoot);while (!EmptyStack(&s)){cur = TopStack(&s);if ((cur->_pLeft == NULL && cur->_pRight == NULL) || ((prev != NULL) && (prev == cur->_pLeft || prev == cur->_pRight))){printf("%c ", cur->_data);PopStack(&s);prev = cur;continue;}if (cur->_pRight)PushStack(&s, cur->_pRight);if (cur->_pLeft)PushStack(&s, cur->_pLeft);}
}
  • 层序遍历:使用到队列的数据结构,我们先将根节点入队列中,进入循环,用temp拿到队首元素,并且打印,然后拿到temp的左右孩子进行入队列,这时顺序必须是先左后有右,因为队列的性质是后进先出的
void LevelOrder(BTNode* pRoot)
{assert(pRoot);Queue q;BTNode* temp = NULL;InitQueue(&q);PushQueue(&q, pRoot);while (!EmptyQueue(&q)){temp = FrontQueue(&q);printf("%c ", temp->_data);if (temp->_pLeft)PushQueue(&q, temp->_pLeft);if (temp->_pRight)PushQueue(&q, temp->_pRight);PopQueue(&q);}
}
  • 拷贝二叉树:采用递归的方式,先拷贝根节点,然后在拷贝左右子树。
BTNode* CopyBinTree(BTNode* pRoot)
{BTNode* pNewRoot = NULL;if (pRoot){pNewRoot = BuyBTNode(pRoot->_data);if (pRoot->_pLeft)pNewRoot->_pLeft = CopyBinTree(pRoot->_pLeft);if (pRoot->_pRight)pNewRoot->_pRight = CopyBinTree(pRoot->_pRight);}return pNewRoot;
}
  • 删除一个二叉树:也是采用递归的方式,先把左右子树删除,在删除根节点,一定要注意这个顺序。一旦先删了根节点,那么他的左右子树就会找不到了。
void DestroyBinTree(BTNode** pRoot)
{assert(pRoot);if (*pRoot){DestroyBinTree(&((*pRoot)->_pLeft));DestroyBinTree(&((*pRoot)->_pRight));free(*pRoot);*pRoot = NULL;}
}
  • 获取二叉树的节点个数:采取递归的方式,最后一定要加上根节点那个1;
int GetBTNodeCount(BTNode* pRoot)
{if (NULL == pRoot)return 0;return GetBTNodeCount(pRoot->_pLeft) + GetBTNodeCount(pRoot->_pRight) + 1;
}
  • 获取叶子节点个数:叶子节点就是此节点的左右孩子都为空。
int GetLeafNodeCount(BTNode* pRoot)
{if (NULL == pRoot)return 0;if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)return 1;return GetLeafNodeCount(pRoot->_pLeft) + GetLeafNodeCount(pRoot->_pRight);
}
  • 获取第K层节点个数:首先要检验参数是否正确,然后第一层只有根节点那就只有1个节点。接下来递归调用就好了。
int GetKLevelNodeCount(BTNode* pRoot, int K)
{if (K <= 0 || pRoot == NULL)return 0;if (K == 1)return 1;return GetKLevelNodeCount(pRoot->_pLeft, K - 1) + GetKLevelNodeCount(pRoot->_pRight, K - 1);}
  • 获取树的高度:定义两个变量,分别表示根节点的左右子树的高度,树的高度就是左右子树最高高度再加上1。
int Height(BTNode* pRoot)
{int LeftHeight = 0;int RightHeight = 0;if (NULL == pRoot)return 0;LeftHeight = Height(pRoot->_pLeft);RightHeight = Height(pRoot->_pRight);return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}
  • 判断节点是否在二叉树中:采用递归的方式,遍历二叉树的所有节点,如果相等那么就返回1,没有就返回0。
int IsBTNodeInBinTree(BTNode* pRoot, BTNode* pNode)
{if (pRoot == NULL || pNode == NULL)return 0;if (pRoot == pNode)return 1;if (IsBTNodeInBinTree(pRoot->_pLeft, pNode))return 1;return IsBTNodeInBinTree(pRoot->_pRight, pNode);
}
  • 获取节点的母亲节点:如果根节点是空或者给的节点是空或者给的节点就是根节点,那么就返回NULL;然后给的节点如果是母亲节点的左孩子或者右孩子,就返回这个节点的母亲节点。
BTNode*  GetBTNodeParent(BTNode* pRoot, BTNode* pNode)
{BTNode* pParent = NULL;if (pRoot == NULL || pNode == NULL || pRoot == pNode)return NULL;if (pNode == pRoot->_pLeft || pNode == pRoot->_pRight)return pRoot;if (pParent = GetBTNodeParent(pRoot->_pLeft, pNode))return pParent;return GetBTNodeParent(pRoot->_pRight, pNode);
}
  • 求二叉树的镜像:采用递归的方式,交换这个节点的左右孩子;接下来处理这个节点的左右孩子。
void Swap(BTNode** Left, BTNode** Right)
{BTNode* temp = *Left;*Left = *Right;*Right = temp;
}void MirrorBinTree(BTNode* pRoot)
{if (pRoot){Swap(&pRoot->_pLeft, &pRoot->_pRight);MirrorBinTree(pRoot->_pLeft);MirrorBinTree(pRoot->_pRight);}
}
  • 求二叉树的镜像:将递归转换为循环,采用栈的循环,近似与前序遍历的思想。
void MirrorBinTreeNor(BTNode* pRoot)
{Queue q;BTNode* temp = NULL;if (NULL == pRoot)return;InitQueue(&q);PushQueue(&q, pRoot);while (!EmptyQueue(&q)){temp = FrontQueue(&q);Swap(&temp->_pLeft, &temp->_pRight);if (temp->_pLeft)PushQueue(&q, temp->_pLeft);if (temp->_pRight)PushQueue(&q, temp->_pRight);PopQueue(&q);}
}
  • 判断是否是完全二叉树:采用队列的数据结构。
  • 如果树为空,则直接返回错
  • 如果树不为空:层序遍历二叉树
  • 如果一个结点左右孩子都不为空,则pop该节点,将其左右孩子入队列;
  • 如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树;
  • 如果遇到一个结点,左孩子不为空,右孩子为空;或者左右孩子都为空;则该节点之后的队列中的结点都为叶子节点;该树才是完全二叉树,否则就不是完全二叉树;
int IsCompleteBinTree(BTNode* pRoot)
{Queue q;BTNode* temp = NULL;int Flag = 0;if (pRoot == NULL)return 1;InitQueue(&q);PushQueue(&q, pRoot);while (!EmptyQueue(&q)){temp = FrontQueue(&q);if (Flag){if (temp->_pLeft || temp->_pRight)return 0;}else{if (temp->_pLeft && temp->_pRight){PushQueue(&q, temp->_pLeft);PushQueue(&q, temp->_pRight);}else if (temp->_pLeft){PushQueue(&q, temp->_pLeft);Flag = 1;}else if (temp->_pRight)return 0;elseFlag = 1;}PopQueue(&q);}
}

最后附上所有代码,包括测试函数,还有需要用到的栈和队列的代码。

  • BTree.h:二叉树的所有函数
#pragma once
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
#include"stack.h"
#include"queue.h"//typedef char DataType;
//
//typedef struct BTNode
//{
//  DataType _data;
//  struct BTNode* _pLeft;
//  struct BTNode* _pRight;
//}BTNode;BTNode* BuyBTNode(DataType data)
{BTNode* temp = (BTNode*)malloc(sizeof(BTNode));if (!temp){assert(0);return;}temp->_data = data;temp->_pLeft = NULL;temp->_pRight = NULL;
}//str 存放元素的数组,size 元素个数,index 递归到那个元素,invalid 树中空位置
void CreateBinTree(BTNode** pRoot, char* str, int size, int* index, DataType invalid)
{assert(pRoot);assert(index);if (*index < size && str[*index] != invalid){*pRoot = BuyBTNode(str[*index]);//创建根节点++(*index);CreateBinTree(&((*pRoot)->_pLeft), str, size, index, invalid);//创建左节点++(*index);CreateBinTree(&((*pRoot)->_pRight), str, size, index, invalid);//创建右节点}
}void PreOrder(BTNode* pRoot)
{if (pRoot == NULL)return;printf("%c ", pRoot->_data);PreOrder(pRoot->_pLeft);PreOrder(pRoot->_pRight);
}void PreOrderNor(BTNode* pRoot)
{assert(pRoot);Stack s;BTNode* temp = NULL;InitStack(&s);PushStack(&s, pRoot);while (!EmptyStack(&s)){temp = TopStack(&s);PopStack(&s);printf("%c ", temp->_data);if (temp->_pRight)PushStack(&s, temp->_pRight);if (temp->_pLeft)PushStack(&s, temp->_pLeft);}
}void InOrder(BTNode* pRoot)
{if (pRoot == NULL)return;InOrder(pRoot->_pLeft);printf("%c ", pRoot->_data);InOrder(pRoot->_pRight);
}void InOrderNor(BTNode* pRoot)
{assert(pRoot);Stack s;BTNode* temp = pRoot;InitStack(&s);while (temp != NULL || !EmptyStack(&s)){        while (temp){PushStack(&s, temp);temp = temp->_pLeft;}temp = TopStack(&s);printf("%c ", temp->_data);PopStack(&s);temp = temp->_pRight;}
}void PostOrder(BTNode* pRoot)
{if (pRoot == NULL)return;PostOrder(pRoot->_pLeft);PostOrder(pRoot->_pRight);printf("%c ", pRoot->_data);
}void PostOrderNor(BTNode* pRoot)
{assert(pRoot);BTNode* cur = NULL;BTNode* prev = NULL;Stack s;InitStack(&s);PushStack(&s, pRoot);while (!EmptyStack(&s)){cur = TopStack(&s);if ((cur->_pLeft == NULL && cur->_pRight == NULL) || ((prev != NULL) && (prev == cur->_pLeft || prev == cur->_pRight))){printf("%c ", cur->_data);PopStack(&s);prev = cur;continue;}if (cur->_pRight)PushStack(&s, cur->_pRight);if (cur->_pLeft)PushStack(&s, cur->_pLeft);}
}void LevelOrder(BTNode* pRoot)
{assert(pRoot);Queue q;BTNode* temp = NULL;InitQueue(&q);PushQueue(&q, pRoot);while (!EmptyQueue(&q)){temp = FrontQueue(&q);printf("%c ", temp->_data);if (temp->_pLeft)PushQueue(&q, temp->_pLeft);if (temp->_pRight)PushQueue(&q, temp->_pRight);PopQueue(&q);}
}BTNode* CopyBinTree(BTNode* pRoot)
{BTNode* pNewRoot = NULL;if (pRoot){pNewRoot = BuyBTNode(pRoot->_data);if (pRoot->_pLeft)pNewRoot->_pLeft = CopyBinTree(pRoot->_pLeft);if (pRoot->_pRight)pNewRoot->_pRight = CopyBinTree(pRoot->_pRight);}return pNewRoot;
}void DestroyBinTree(BTNode** pRoot)
{assert(pRoot);if (*pRoot){DestroyBinTree(&((*pRoot)->_pLeft));DestroyBinTree(&((*pRoot)->_pRight));free(*pRoot);*pRoot = NULL;}
}int GetBTNodeCount(BTNode* pRoot)
{if (NULL == pRoot)return 0;return GetBTNodeCount(pRoot->_pLeft) + GetBTNodeCount(pRoot->_pRight) + 1;
}int GetLeafNodeCount(BTNode* pRoot)
{if (NULL == pRoot)return 0;if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)return 1;return GetLeafNodeCount(pRoot->_pLeft) + GetLeafNodeCount(pRoot->_pRight);
}int GetKLevelNodeCount(BTNode* pRoot, int K)
{if (K <= 0 || pRoot == NULL)return 0;if (K == 1)return 1;return GetKLevelNodeCount(pRoot->_pLeft, K - 1) + GetKLevelNodeCount(pRoot->_pRight, K - 1);}int Height(BTNode* pRoot)
{int LeftHeight = 0;int RightHeight = 0;if (NULL == pRoot)return 0;LeftHeight = Height(pRoot->_pLeft);RightHeight = Height(pRoot->_pRight);return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}int IsBTNodeInBinTree(BTNode* pRoot, BTNode* pNode)
{if (pRoot == NULL || pNode == NULL)return 0;if (pRoot == pNode)return 1;if (IsBTNodeInBinTree(pRoot->_pLeft, pNode))return 1;return IsBTNodeInBinTree(pRoot->_pRight, pNode);
}BTNode*  GetBTNodeParent(BTNode* pRoot, BTNode* pNode)
{BTNode* pParent = NULL;if (pRoot == NULL || pNode == NULL || pRoot == pNode)return NULL;if (pNode == pRoot->_pLeft || pNode == pRoot->_pRight)return pRoot;if (pParent = GetBTNodeParent(pRoot->_pLeft, pNode))return pParent;return GetBTNodeParent(pRoot->_pRight, pNode);
}void Swap(BTNode** Left, BTNode** Right)
{BTNode* temp = *Left;*Left = *Right;*Right = temp;
}void MirrorBinTree(BTNode* pRoot)
{if (pRoot){Swap(&pRoot->_pLeft, &pRoot->_pRight);MirrorBinTree(pRoot->_pLeft);MirrorBinTree(pRoot->_pRight);}
}void MirrorBinTreeNor(BTNode* pRoot)
{Queue q;BTNode* temp = NULL;if (NULL == pRoot)return;InitQueue(&q);PushQueue(&q, pRoot);while (!EmptyQueue(&q)){temp = FrontQueue(&q);Swap(&temp->_pLeft, &temp->_pRight);if (temp->_pLeft)PushQueue(&q, temp->_pLeft);if (temp->_pRight)PushQueue(&q, temp->_pRight);PopQueue(&q);}
}int IsCompleteBinTree(BTNode* pRoot)
{Queue q;BTNode* temp = NULL;int Flag = 0;if (pRoot == NULL)return 1;InitQueue(&q);PushQueue(&q, pRoot);while (!EmptyQueue(&q)){temp = FrontQueue(&q);if (Flag){if (temp->_pLeft || temp->_pRight)return 0;}else{if (temp->_pLeft && temp->_pRight){PushQueue(&q, temp->_pLeft);PushQueue(&q, temp->_pRight);}else if (temp->_pLeft){PushQueue(&q, temp->_pLeft);Flag = 1;}else if (temp->_pRight)return 0;elseFlag = 1;}PopQueue(&q);}
}BTNode* LeftChild(BTNode* pNode)
{return (NULL != pNode) ? pNode->_pLeft : NULL;
}BTNode* RightChild(BTNode* pNode)
{return (NULL != pNode) ? pNode->_pRight : NULL;
}#include<string.h>void TestBTree()
{char* pStr = "ABD###CE##F";BTNode* pRoot = NULL;int index = 0;BTNode* pRootC = NULL;CreateBinTree(&pRoot, pStr, strlen(pStr), &index, '#');printf("二叉树中节点的总个数为: %d\n", GetBTNodeCount(pRoot));printf("二叉树中叶子节点的总个数为: %d\n", GetLeafNodeCount(pRoot));printf("二叉树第3层中节点的个数为: %d\n", GetKLevelNodeCount(pRoot, 3));printf("二叉树的高度为: %d\n", Height(pRoot));if (IsCompleteBinTree(pRoot))printf("是完全二叉树!!!\n");elseprintf("不是完全二叉树!!!\n");MirrorBinTree(pRoot);MirrorBinTreeNor(pRoot);printf("前序递归遍历:");PreOrder(pRoot);printf("\n");printf("前序非递归遍历:");PreOrderNor(pRoot);printf("\n");printf("中序遍历:");InOrder(pRoot);printf("\n");printf("中序非递归遍历:");InOrderNor(pRoot);printf("\n");printf("后续遍历:");PostOrder(pRoot);printf("\n");printf("后续非递归遍历:");PostOrderNor(pRoot);printf("\n");printf("层序遍历:");LevelOrder(pRoot);printf("\n");pRootC = CopyBinTree(pRoot);printf("前序遍历:");PreOrder(pRootC);printf("\n");printf("中序遍历:");InOrder(pRootC);printf("\n");printf("后续遍历:");PostOrder(pRootC);printf("\n");DestroyBinTree(&pRoot);DestroyBinTree(&pRootC);
}
  • stack.c:栈的函数
#pragma once
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>#define INITSIZE 100
#define INCREASESIZE 10typedef char DataType;typedef struct BTNode
{DataType _data;struct BTNode* _pLeft;struct BTNode* _pRight;
}BTNode;typedef BTNode* SDataType;typedef struct Stack {SDataType* array;int size;int capacity;
}Stack;void InitStack(Stack* s)
{assert(s);s->array = (SDataType*)malloc(INITSIZE*sizeof(SDataType));if (!s->array){assert(0);return;}s->capacity = INITSIZE;s->size = 0;
}void PushStack(Stack* s, SDataType data)
{assert(s);if (s->size >= s->capacity){s->array = (SDataType*)realloc(s->array,(s->capacity + INCREASESIZE)* sizeof(SDataType));if (!s->array){assert(0);return;}s->capacity = s->capacity + INCREASESIZE;}s->array[s->size] = data;s->size++;
}void PopStack(Stack* s)
{assert(s);if (s->size == 0)return;elses->size--;
}SDataType TopStack(Stack* s)
{assert(s);if (s->size == 0){assert(0);return;}return (s->array[s->size - 1]);
}int SizeStack(Stack* s)
{assert(s);return s->size;
}int EmptyStack(Stack* s)
{assert(s);if (s->size == 0)return 1;elsereturn 0;
}
  • queue.c:队列的函数
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"stack.h"typedef BTNode* LDataType;typedef struct Node{LDataType _data;struct Node* _next;
}Node;typedef Node QDataType;typedef struct Queue{QDataType* front;QDataType* rear;int size;
}Queue;void InitQueue(Queue* q)
{assert(q);q->rear = (QDataType*)malloc(sizeof(QDataType));if (!q->front){assert(0);return;}q->front = q->rear;q->size = 0;
}void PushQueue(Queue* q, LDataType data)
{assert(q);QDataType* new_node = NULL;if (q->size == 0){q->rear->_data = data;q->size++;}else{new_node = (QDataType*)malloc(sizeof(QDataType));if (!new_node){assert(0);return;}new_node->_data = data;new_node->_next = NULL;q->rear->_next = new_node;q->rear = new_node;q->size++;}
}void PopQueue(Queue* q)
{assert(q);QDataType* temp = NULL;if (q->size == 0){return;}else if (q->size == 1){q->size--;}else{temp = q->front->_next;free(q->front);q->front = temp;q->size--;}
}LDataType FrontQueue(Queue* q)
{assert(q);if (q->size == 0)return NULL;elsereturn q->front->_data;
}int EmptyQueue(Queue* q)
{assert(q);if (q->size == 0)return 1;return 0;
}
  • 测试函数
#include"BTree.h"int main()
{TestBTree();return 0;
}

总结:递归的思想应该懂得,还有栈和队列的思想解决问题。有什么问题的话欢迎下方留言。

详细解读二叉树基本操作相关推荐

  1. NLP突破性成果 BERT 模型详细解读 bert参数微调

    https://zhuanlan.zhihu.com/p/46997268 NLP突破性成果 BERT 模型详细解读 章鱼小丸子 不懂算法的产品经理不是好的程序员 ​关注她 82 人赞了该文章 Goo ...

  2. VINS-mono详细解读与实现

    VINS-mono详细解读 VINS-mono详细解读 前言 Vins-mono是香港科技大学开源的一个VIO算法,https://github.com/HKUST-Aerial-Robotics/V ...

  3. R回归模型输出结果详细解读:summary、call、residuals、Coefficients、Assessing Model Fit

    R回归模型输出结果详细解读:summary.call.residuals.Coefficients.Assessing Model Fit 目录 R回归模型输出结果详细解读:summary.call. ...

  4. MemCache超详细解读

    MemCache是什么 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高 ...

  5. CSS 详细解读定位属性 position 以及参数

    Css 详细解读定位属性 position 以及参数 position 定位属性,是CSS中非常重要的属性.除了文档流布局,就是定位布局了.本来我对这个问题没有放在心上,毕竟写了这么多年的css,对p ...

  6. MemCache详细解读

    MemCache是什么 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高 ...

  7. 直播 | 腾讯天衍实验室张子恒:详细解读天衍实验室知识图谱对齐技术

    「AI Drive」是由 PaperWeekly 和 biendata 共同发起的学术直播间,旨在帮助更多的青年学者宣传其最新科研成果.我们一直认为,单向地输出知识并不是一个最好的方式,而有效地反馈和 ...

  8. 数据结构 【实验7 二叉树基本操作】

    实验7   二叉树基本操作 实验目的 1.  熟悉二叉树结点的结构和对二叉树的基本操作. 2.  掌握对二叉树每一种操作的具体实现. 3.  学会利用递归方法编写对二叉树这种递归数据结构进行处理的算法 ...

  9. Madgwick算法详细解读

    Madgwick算法详细解读 极品巧克力 前言 接上一篇文章<Google Cardboard的九轴融合算法>. Madgwick算法是另外一种九轴融合的方法,广泛应用在旋翼飞行器上,效果 ...

  10. Transformer详细解读与预测实例记录

    文章目录 Transformer详细解读与预测实例记录 1.位置编码 1)输入部分: 2)位置编码部分: 2.多头注意力机制 1)基本注意力机制 2)transformer中的注意力 3.残差和Lay ...

最新文章

  1. 5、C语言面试笔试--数据组织--数组
  2. 稠密峰值聚类 - Science2014
  3. SpringCloud Eureka自我保护机制
  4. mysql引擎inndbmmyisam_Mysql中MyISAM引擎和InnoDB引擎的比较
  5. sql日期处理(出自邹建的book)
  6. 常见移动机器人轮直径校准实验思路
  7. notepad++ 配置C/C++环境
  8. 内存颗粒位宽和容量_内存颗粒编码原则,方便大家识别颗粒是否可用与扩容
  9. 向量点积衡量相似度_向量点积与叉积
  10. 使用PS更改照片的背景色
  11. 蓝牙sbc怎么解决_你不知道蓝牙耳机术语,看懂了才明白哪些是优质蓝牙耳机
  12. 常用遥感SIF和GPP数据集
  13. 哈啰A80青春版体验:避繁就简,享受智慧骑行带来的乐趣
  14. 解决NVIDIA显卡驱动 图形驱动程序安装失败 问题
  15. 诺基亚联手迪信通 力推内置仙剑三版5230手机
  16. MySQL数据库(三)-表行的语句使用
  17. 关于gist.github.com网站不能访问的解决办法
  18. win7下怎么配置ODBC数据源
  19. CSS 中最后一行中元素如何向左对齐
  20. struct2破绽及升级

热门文章

  1. vs2019配置opencv_VS2019下Opencv配置
  2. 在计算机操作系统中操作系统是处于应用软件,计算机操作系统应用试题与答案.pdf...
  3. jpa删除数据后数据库无修改_jpa删除数据库
  4. 谷粒商城:06. 前端开发基础知识
  5. Vue:不使用webpack情况下将Cesium引入到Vue项目中
  6. linux进程管理概念,Linux教程之进程的概念和进程管理命令的使用
  7. java将excel转换成txt_java将excel文件转换成txt格式文件
  8. 使用内存文件映射MappedByteBuffer读超大文件可能会遇到的问题
  9. PM_敏捷开发 Scrum vs Kanban,如何选择?
  10. 论文笔记_S2D.40_2017_CVPR_半监督深度学习的单目深度图预测