初识二叉树:

本文详细介绍了二叉树的基本特点、不同形态(如空二叉树、斜树、满二叉树和完全二叉树)、性质、存储结构(顺序和链式),以及前序、中序、后序和层序遍历的递归和迭代实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树:

二叉树基本特点:

  1. 每个节点最多只有两个子树,没有子树或者只有一个子树都是ok的。
  2. 左右子树有序的,一个节点如果有两个子树必须区分左右子树,即使只有一个子树也必须区分其是左子树还是右子树。

二叉树基本形态:

  1. 空二叉树
  2. 只有一个空结点。
  3. 根结点只有左子树。
  4. 根结点只有右子树
  5. 根结点既有左子树还有右子树。

特殊二叉树及其特点:

  1. 斜树:即一颗树只有左结点或者只有右结点。只有左结点称为左斜树,只有右结点称为右斜树。特点是每一层只有一个结点,即树的深度等于结点的个数。
  2. 满二叉树:一颗树所有的分支结点既有左子树也有右子树,并且叶都在同一层上,即为满二叉树。
  3. 完全二叉树:简单来说,除了最后一层结点之外,其他层结点必须有两颗子树,并且最后一层结点必须左排列。满二叉树必是完全二叉树。至于完全二叉树名字的由来,其实是和其存储结构有关。[具体详见](完全二叉树看起来并不完全,为什么叫完全二叉树呢? - 知乎 (zhihu.com))

二叉树的性质:

​ 性质1:二叉树第i层上的结点个数最多是2^(i - 1)。

​ 性质2:深度为k的二叉树最多有2^(k) - 1个节点(满二叉树)。

​ 性质3:包含n个结点的二叉树深度至少为log2(n)+ 1。

​ 性质4:任意一棵二叉树中,叶子结点的个数为n0(度为0),度为2的结点的个数为n2,则有

​ n0 = n2 + 1。

​ 性质5:对于完全二叉树而言,对于第i个结点,若其有左子树,则其左子结点为2i,若其有右子树,则右子 结点为2i + 1,当然,左右子结点的大小不能大于结点总数n。

二叉树的存储结构:

顺序存储结构:

一般只适用于完全二叉树,因为可以最大限度的利用内存空间而不至于被浪费。[具体详见](完全二叉树看起来并不完全,为什么叫完全二叉树呢? - 知乎 (zhihu.com))

链式存储结构:

链式存储结构避免了空间上的浪费。

一般形式为

typedef struct TreeNode{
	Type data;
	struct TreeNode* left;
	struct TreeNode* right;
}

当然也可以再加一个指向其父母的指针。

typedef struct TreeNode{
	Type data;
	struct TreeNode* left;
	struct TreeNode* right;
	struct TreeNode* parents;
	
}

遍历二叉树:

其实对于任何一种数据结构来说,最重要的莫过于遍历了,不然存了啥数据用不了都白瞎,二叉树的遍历最基础的有两种方式,递归和迭代。根据遍历顺序的不同又可以分为前序遍历,中序遍历,后序遍历,层序遍历。
其中递归和迭代本质上都是对于栈的运用,递归是隐式栈,迭代则是运用了前面学过的栈来显式的模拟递归函数压栈的方式。
当然,层序遍历则是用队列来模拟。

typedef struct TreeNode{
	int val;
	struct TreeNode* left;
	struct TreeNode* right;
}

1.前序遍历:

遍历顺序:中左右。深度优先
原题链接:

144. 二叉树的前序遍历

递归实现:

中左右,递归一直往左走,沿路处理中间结点,到头找右。

void pre(struct TreeNode* root,int* rev, int* returnSize){
    if(root==NULL){
        return;
    }
    rev[(*returnSize)++] = root->val;
    //*(rev + (*returnSize)++) = root->val;
    pre(root->left, rev, returnSize);
    pre(root->right, rev, returnSize);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    int *rev = (int*)malloc(sizeof(int)*100);
    *returnSize = 0;
    if(root==NULL){
        return rev;
    }
    pre(root, rev, returnSize);
    return rev;
}
迭代实现:

​ 通过栈来实现迭代前序遍历。如果指针不为空就往左走,沿路处理中间结点,将中间结点压栈(方便等会找到右结点),到左边为空之后把栈顶元素出栈,往右走。循环执行往左走,存中间,再往右的过程,最后遍历完成整棵树。

int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    int *rev = (int*)malloc(sizeof(int)*100);
    *returnSize = 0;
    struct TreeNode* stack[100];
    if(root==NULL){
        return rev;
    }
    struct TreeNode* p = root;
    int top = 0;
    while(top > 0||p != NULL){
        while(p != NULL){
            *(rev + (*returnSize)++) = p ->val;
            stack[top++] = p;
            p = p->left;
        }
        p = stack[--top];
        p = p->right;
    }
    return rev;
}

2.中序遍历:

遍历顺序:左中右,深度优先。
原题链接:

94. 二叉树的中序遍历

递归实现:
void inorder(struct TreeNode* root, int* rev, int *returnSize){
    if(root==NULL){
        return;
    }
    inorder(root->left, rev, returnSize);
    //*(rev+*returnSize++) = root->val;
    *(rev + (*returnSize)++) = root->val;
    inorder(root->right, rev, returnSize);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize) {
    int* rev = (int*)malloc(sizeof(int)*100);
    *returnSize = 0;
    inorder(root, rev, returnSize);
    return rev;
}
迭代实现:
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
    int* rev = (int*)malloc(sizeof(int)*100);
    struct TreeNode* stack[100];
    *returnSize = 0;
    int top = 0;
    while(root != NULL || top > 0){
        while(root!=NULL){
            stack[top++] = root;
            root = root->left;
        }
        root = stack[--top];
        *(rev + (*returnSize)++) = root->val;
        root = root->right;
    }
    return rev;
}

3.后序遍历:

遍历顺序:左右中,深度优先。
题目链接:

145. 二叉树的后序遍历

递归实现:
void postorder(struct TreeNode* root ,int* nums, int* returnSize){
    if(root==NULL){
        return;
    }
     postorder(root->left, nums,returnSize);
      postorder(root->right, nums,returnSize);
    *(nums+(*returnSize)++) = root->val;
}

int* postorderTraversal(struct TreeNode* root, int* returnSize) {
    *returnSize = 0;
    int *nums = (int*)malloc(sizeof(int)*100);
    postorder(root, nums,returnSize);
    return nums;
}
迭代实现:
int *postorderTraversal(struct TreeNode *root, int *returnSize) {
    int *res = malloc(sizeof(int) * 2001);
    *returnSize = 0;
    if (root == NULL) {
        return res;
    }
    struct TreeNode* stack[100];
    int top = 0;
    struct TreeNode *prev = NULL;
    while (root != NULL || top > 0) {
        while (root != NULL) {
            stack[top++] = root;//不为空一直找最左边的
            root = root->left;
        }
        root = stack[--top];//为空了弹出栈顶结点往右边找

        //为了先一直找到最右边的再标记找过右边的不往右边找
        if (root->right == NULL || root->right == prev) {
            res[(*returnSize)++] = root->val;
            prev = root;//记录找过右边的结点
            root = NULL;//置root为空跳过第一个while不往左边找
        } else {
            stack[top++] = root; 
            root = root->right;
        }
    }
    return res;
}

4.层序遍历:

遍历顺序:层层遍历,从左到右,广度优先。

原题链接:

102. 二叉树的层序遍历

迭代实现:
int** levelOrder(struct TreeNode* root,int* returnSize,int** returnColumnSizes){
    *returnSize = 0;
    if(root == NULL)
        return NULL;
    int** res = (int**)malloc(sizeof(int*) * 2000);
    *returnColumnSizes = (int*)malloc(sizeof(int) * 2000);
    struct TreeNode* queue[2000];
    int front = 0;
    int rear = 0;
    struct TreeNode* p;
    queue[rear++] = root;
    while(front != rear){
        int colSize = 0,last = rear;
        res[*returnSize] = (int*)malloc(sizeof(int) * (last - front));
        while(front < last){
            p = queue[front++];
            res[*returnSize][colSize++] = p ->val;
            if(p -> left != NULL)//结点不为空左右结点先后入队
                queue[rear++] = p -> left;
            if(p -> right != NULL)
                queue[rear++] = p -> right;
        }
        (*returnColumnSizes)[*returnSize] = colSize;
        (*returnSize)++;
    }
    return res;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值