第五章树与二叉树

1.顺序存储

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 100

// 用数组表示二叉树
/*
    这段代码将数组 tree 和变量 size 放在 main 函数外部,这是为了使它们成为全局变量。
    在C语言中,全局变量可以在整个程序中访问,而不仅仅局限于 main函数
*/
int tree[MAX_SIZE];
int size = 0;

// 插入元素到顺序存储的二叉树中
void insert(int value) {
    if (size >= MAX_SIZE) {
        printf("二叉树已满,无法插入新元素\n");
        return;
    }
    tree[size] = value;
    size++;
}

// 先序遍历二叉树
void preOrder(int index) {
    if (index >= size) return;

    printf("%d ", tree[index]);
    preOrder(2 * index + 1); // 左子树
    preOrder(2 * index + 2); // 右子树
}

// 中序遍历二叉树
void inOrder(int index) {
    if (index >= size) return;

    inOrder(2 * index + 1); // 左子树
    printf("%d ", tree[index]);
    inOrder(2 * index + 2); // 右子树
}

// 后序遍历二叉树
void postOrder(int index) {
    if (index >= size) return;

    postOrder(2 * index + 1); // 左子树
    postOrder(2 * index + 2); // 右子树
    printf("%d ", tree[index]);
}

int main() {
    insert(1);
    insert(2);
    insert(3);
    insert(4);
    insert(5);
    printf("先序遍历结果: ");
    preOrder(0); // 从根节点开始遍历
    printf("\n");

    printf("中序遍历结果: ");
    inOrder(0); // 从根节点开始遍历
    printf("\n");

    printf("后序遍历结果: ");
    postOrder(0); // 从根节点开始遍历
    printf("\n");

    return 0;
}

2.链式存储

#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构体
typedef struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode) {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }
    return newNode;
}

// 插入节点到二叉树(按照从左到右,从上到下的顺序插入)
// 插入节点到二叉树(按照从左到右、从上到下的顺序插入)
TreeNode* insert(TreeNode* root, int data) {
    // 创建一个新节点
    TreeNode* newNode = createNode(data);

    if (root == NULL) {
        return newNode; // 如果根节点为空,直接将新节点作为根节点返回
    } else {
        // 使用队列来按照从左到右、从上到下的顺序插入节点
        TreeNode* queue[100]; // 假设最多100个节点
        int front = -1, rear = -1;

        // 将根节点入队
        queue[++rear] = root;

        while (1) {
            TreeNode* current = queue[++front];

            if (current->left == NULL) {
                current->left = newNode;
                break; // 插入完成后退出循环
            } else {
                queue[++rear] = current->left;
            }

            if (current->right == NULL) {
                current->right = newNode;
                break; // 插入完成后退出循环
            } else {
                queue[++rear] = current->right;
            }
        }
        return root;
    }
}


// 前序遍历函数
void preorderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    printf("%d ", root->data);
    preorderTraversal(root->left);
    preorderTraversal(root->right);
}

// 中序遍历函数
void inorderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    inorderTraversal(root->left);
    printf("%d ", root->data);
    inorderTraversal(root->right);
}

// 后序遍历函数
void postorderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    postorderTraversal(root->left);
    postorderTraversal(root->right);
    printf("%d ", root->data);
}

// 层次遍历函数
void levelOrderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }

    // 创建一个队列用于层次遍历
    TreeNode* queue[100]; // 假设最多100个节点
    int front = -1, rear = -1;          //front指向对头 rear指向队尾
    // 将根节点入队
    queue[++rear] = root;
    while (front != rear) {         //出队进队时 front rear后移,当front==rear==-1时 对空
        // 出队并访问节点
        TreeNode* current = queue[++front];     // current 始终指向对头节点
        printf("%d ", current->data);

        // 将左子节点入队
        if (current->left != NULL) {
            queue[++rear] = current->left;
        }

        // 将右子节点入队
        if (current->right != NULL) {
            queue[++rear] = current->right;
        }
    }
}

int main() {
    TreeNode* root = NULL;
    int values[] = {1, 2, 3, 4, 5, 6, 7};
    int numNodes = sizeof(values) / sizeof(values[0]);

    // 依次插入节点到二叉树
    for (int i = 0; i < numNodes; i++) {
        root = insert(root, values[i]);
    }

    printf("前序遍历结果:");
    preorderTraversal(root);
    printf("\n");

    printf("中序遍历结果:");
    inorderTraversal(root);
    printf("\n");

    printf("后序遍历结果:");
    postorderTraversal(root);
    printf("\n");

    printf("层次遍历结果:");
    levelOrderTraversal(root);
    printf("\n");
    return 0;
}

中序、后序、先序非递归

#include <stdio.h>
#include <stdbool.h>
#define MaxSize 100
typedef struct Tree {
    int data;
    struct Tree* lchild;
    struct Tree* rchild;
} Node, *Tree;

int main() {
    // 构建一棵二叉树
    Tree root = (Tree)malloc(sizeof(Node));
    root->data = 1;
    root->lchild = (Tree)malloc(sizeof(Node));
    root->lchild->data = 2;
    root->lchild->lchild = (Tree)malloc(sizeof(Node));
    root->lchild->lchild->data = 4;
    root->lchild->lchild->lchild = NULL;
    root->lchild->lchild->rchild = NULL;
    root->lchild->rchild = (Tree)malloc(sizeof(Node));
    root->lchild->rchild->data = 5;
    root->lchild->rchild->lchild = NULL;
    root->lchild->rchild->rchild = NULL;
    root->rchild = (Tree)malloc(sizeof(Node));
    root->rchild->data = 3;
    root->rchild->lchild = (Tree)malloc(sizeof(Node));
    root->rchild->lchild->data = 6;
    root->rchild->lchild->lchild = NULL;
    root->rchild->lchild->rchild = NULL;
    root->rchild->rchild = NULL;
    // 中序遍历
    printf("中序遍历: ");
    InOrder(root);
    printf("\n");
    
    // 前序遍历
    printf("前序遍历: ");
    PreOrder(root);
    printf("\n");

    // 后序遍历
    printf("后序遍历: ");
    PostOrder(root);
    printf("\n");
    return 0;
}
// 非递归方式实现二叉树的中序遍历
void InOrder(Tree bt) {
    Node* stack[MaxSize];	 // 模拟递归的栈
    int top = -1;	// 栈顶指针
    Node* p = bt;	// 当前节点指针

    // 当前节点不为空或栈非空时,进行遍历
    while (p != NULL || top != -1) {
        // 将左子树所有节点入栈,直到达到最左的叶子节点
        while (p != NULL) {
            stack[++top] = p; // 将当前节点入栈
            p = p->lchild;    // 移动到左子节点
        }

        // 如果栈非空,弹出一个节点
        if (top != -1) {
            p = stack[top--];       // 弹出一个节点
            printf("%d ", p->data); // 处理当前节点,例如打印节点数据
            p = p->rchild;           // 移动到右子节点
        }
    }
}

// -----------------------------------------------非递归后序遍历
void PostOrder(Tree bt) {
    Node* stack1[MaxSize];
    Node* stack2[MaxSize];
    int top1 = -1;
    int top2 = -1;
    Node* p = bt;
    // 先将树的根节点入栈1
    stack1[++top1] = p;

    // 在栈1不为空时,循环执行以下操作
    while (top1 != -1) {
        p = stack1[top1--];      // 弹出栈1的栈顶元素
        stack2[++top2] = p;      // 将该元素压入栈2

        if (p->lchild != NULL) {
            stack1[++top1] = p->lchild; // 如果有左子节点,将左子节点入栈1
        }

        if (p->rchild != NULL) {
            stack1[++top1] = p->rchild; // 如果有右子节点,将右子节点入栈1
        }
    }

    // 将栈2中的元素打印,即为后序遍历结果
    while (top2 != -1) {
        p = stack2[top2--];
        printf("%d ", p->data); // 处理当前节点,例如打印节点数据
    }
}

// -----------------------------------------------非递归前序遍历
void PreOrder(Tree bt) {
    Node* stack[MaxSize];
    int top = -1;
    Node* p = bt;

    while (p != NULL || top != -1) {
        while (p != NULL) {
            printf("%d ", p->data); // 处理当前节点,例如打印节点数据
            stack[++top] = p;        // 将当前节点入栈
            p = p->lchild;           // 移动到左子节点
        }

        if (top != -1) {
            p = stack[top--];    // 弹出一个节点
            p = p->rchild;       // 移动到右子节点
        }
    }
}

3.习题

5.非递归求书高(层次和后序)

#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构体
typedef struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode) {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }
    return newNode;
}

// 后序遍历方式求二叉树高度的非递归函数
int getHeight1(TreeNode* root) {
    if (root == NULL) {
        return 0;
    }

    int height = 0;
    int maxHeight = 0;
    TreeNode* current = NULL;
    TreeNode* lastVisit = NULL;

    // 创建一个栈用于后序遍历
    TreeNode* stack[100]; // 假设最多100个节点
    int top = -1;

    while (root != NULL || top != -1) {
        while (root != NULL) {
            stack[++top] = root;
            root = root->left;
        }

        current = stack[top];

        // 右子树为空或已经访问过,可以访问当前节点
        if (current->right == NULL || current->right == lastVisit) {
            height = top + 1; // 当前栈的大小即为高度
            maxHeight = (height > maxHeight) ? height : maxHeight;
            lastVisit = current;
            top--;
        } else {
            root = current->right;
        }
    }

    return maxHeight;
}

// 层次遍历方式求二叉树高度的非递归函数
int getHeight2(TreeNode* root) {
    if (root == NULL) {
        return 0;
    }

    int height = 0;
    TreeNode* current = NULL;

    // 创建一个队列用于层次遍历
    TreeNode* queue[100]; // 假设最多100个节点
    int front = -1, rear = -1;

    // 将根节点入队
    queue[++rear] = root;

    while (front != rear) {
        int levelSize = rear - front; // 当前层级的节点数量

        while (levelSize > 0) {
            current = queue[++front];

            if (current->left != NULL) {
                queue[++rear] = current->left;
            }

            if (current->right != NULL) {
                queue[++rear] = current->right;
            }

            levelSize--;
        }

        height++; // 每遍历完一层,高度加1
    }

    return height;
}

int main() {
    TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->left = createNode(6);
    root->right->right = createNode(7);
    root->left->left->left = createNode(8);

    int height1 = getHeight1(root);
    printf("二叉树的高度为: %d\n", height1);
    int height2 = getHeight2(root);
    printf("二叉树的高度为: %d\n", height2);
    return 0;
}

8.计算二叉树所有双分支节点

#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构体
typedef struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode) {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }
    return newNode;
}

// 计算二叉树中双分支节点的数量
int countDoubleBranchNodes(TreeNode* root) {
    if (root == NULL)
        return 0;

    // 递归计算左子树和右子树中双分支节点的数量
    int leftCount = countDoubleBranchNodes(root->left);
    int rightCount = countDoubleBranchNodes(root->right);

    // 如果当前节点同时有左子树和右子树,那么它是一个双分支节点
    if (root->left != NULL && root->right != NULL) {
        return leftCount + rightCount + 1;
    } else {
        return leftCount + rightCount;
    }
}

int main() {
    // 创建一个二叉树示例
    TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->left = createNode(6);
    root->right->right = createNode(7);

    // 计算双分支节点的数量
    int doubleBranchNodeCount = countDoubleBranchNodes(root);

    printf("二叉树中双分支节点的数量为: %d\n", doubleBranchNodeCount);
    return 0;
}

11.删除所有值为x的节点以及子树

#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构体
typedef struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode) {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }
    return newNode;
}

// 删除以root为根的子树,并释放内存
void deleteSubtree(TreeNode* root) {
    if(root){
        // 递归删除左子树和右子树
        deleteSubtree(root->left);
        deleteSubtree(root->right);

        // 释放当前节点的内存
        free(root);
    }
}

// 删除二叉树中所有值为num的节点及其子树
TreeNode* deleteNodesWithValue(TreeNode* root, int num) {
    if (root) {
        // 递归处理左子树和右子树
        root->left = deleteNodesWithValue(root->left, num);
        root->right = deleteNodesWithValue(root->right, num);

        // 如果当前节点的值等于num,删除以当前节点为根的子树并释放内存
        if (root->data == num) {
            deleteSubtree(root);
            return NULL; // 返回NULL表示当前节点及其子树已被删除
        }
        return root;
    }
}

// 前序遍历函数(用于验证删除结果)
void preorderTraversal(TreeNode* root) {
    if (root == NULL) {
        return;
    }
    printf("%d ", root->data);
    preorderTraversal(root->left);
    preorderTraversal(root->right);
}

int main() {
    // 创建一个示例二叉树
    TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(2);
    root->right->left = createNode(2);
    root->right->right = createNode(5);

    int numToDelete = 2; // 要删除的节点值

    printf("删除前的二叉树前序遍历结果:");
    preorderTraversal(root);
    printf("\n");

    // 删除所有值为numToDelete的节点及其子树
    root = deleteNodesWithValue(root, numToDelete);

    printf("删除后的二叉树前序遍历结果:");
    preorderTraversal(root);
    printf("\n");
    return 0;
}

12.寻找值为x所有祖先

1.递归实现

#include <stdio.h>
#include <stdlib.h>

// 定义二叉树节点结构体
typedef struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode) {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }
    return newNode;
}

// 查找值为x的节点的所有祖先节点
int findAncestors(TreeNode* root, int x) {
    if (root == NULL) {
        return 0; // 未找到,返回0表示没有找到值为x的节点
    }

    // 如果当前节点的值等于x,返回1表示找到了
    if (root->data == x) {
        return 1;
    }

    // 在左子树中查找
    int foundInLeft = findAncestors(root->left, x);

    // 如果在左子树中找到了,或者在右子树中找到了,说明当前节点是祖先之一
    if (foundInLeft || findAncestors(root->right, x)) {
        printf("%d ", root->data); // 输出当前节点值,表示找到了一个祖先
        return 1; // 返回1表示已经找到
    }

    return 0; // 否则返回0表示未找到
}

int main() {
    TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->left = createNode(6);
    root->right->right = createNode(7);

    int x = 5; // 要查找祖先的节点值
    printf("值为 %d 的节点的所有祖先是:\n", x);
    findAncestors(root, x);
    printf("\n");
    return 0;
}

2.非递归(没理解)

#include <stdio.h>
#include <stdlib.h>

// 定义二叉树节点结构体
typedef struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode) {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }
    return newNode;
}
/*
代码大意:
    一直向左下遍历直到叶子结点并将遍历到的节点依次进栈(后进先出),
    到了叶子结点 先判断父节点右子树是否为空 并且是否不是为pre先前操作过的子树,将current改为右兄弟


*/

// 非递归后序遍历实现查找值为x的节点的所有祖先
void findAncestors(TreeNode* root, int x) {
    if (root == NULL) {
        printf("未找到节点 %d\n", x);
        return;
    }

    TreeNode* stack[100]; // 假设最多100个节点作为祖先
    int top = -1;
    TreeNode* current = root;
    TreeNode* prev = NULL;

    while (current || top != -1) {
        while (current) {
            stack[++top] = current;     //进栈
            current = current->left;
        }

        current = stack[top];

        if (current->right && current->right != prev) {
            current = current->right;
        } else {
            if (current->data == x) {
                // 找到节点x,输出祖先
                printf("值为 %d 的节点的祖先是:", x);
                for (int i = 0; i < top; i++) {
                    printf("%d ", stack[i]->data);
                }
                printf("\n");
                return;
            }

            prev = current;
            top--;  //出栈
            current = NULL;
        }
    }

    printf("未找到节点 %d\n", x);
}

int main() {
    TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->left = createNode(6);
    root->right->right = createNode(7);
    root->left->left->left = createNode(8);
    root->left->left->right = createNode(9);
    root->left->right->left = createNode(10);
    root->left->right->right = createNode(11);

    int x = 10;
    findAncestors(root, x);
    return 0;
}

13.寻找两节点公共祖先

1.递归

#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构体
typedef struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建新的二叉树节点
TreeNode* createNode(int data) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode) {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }
    return newNode;
}

// 查找二叉树中的公共祖先
TreeNode* findLowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    if (root == NULL) {
        return NULL; // 如果树为空,返回NULL
    }

    if (root == p || root == q) {
        return root; // 如果当前节点等于p或q,说明找到了一个目标节点,返回当前节点
    }

    // 递归查找左子树和右子树
    TreeNode* left = findLowestCommonAncestor(root->left, p, q);
    TreeNode* right = findLowestCommonAncestor(root->right, p, q);

    // 如果左子树和右子树都找到了目标节点,说明当前节点是最近的公共祖先
    if (left && right) {
        return root;
    }

    // 如果只找到一个目标节点,返回那个节点,否则返回NULL
    return left ? left : right;
}

int main() {
    TreeNode* root = createNode(3);
    root->left = createNode(5);
    root->right = createNode(1);
    root->left->left = createNode(6);
    root->left->right = createNode(2);
    root->right->left = createNode(0);
    root->right->right = createNode(8);
    root->left->right->left = createNode(7);
    root->left->right->right = createNode(4);

//    TreeNode* p = root->left;  // 假设p为节点5
    TreeNode* p = root->left->right->left;  // 假设p为节点7
    TreeNode* q = root->left->right->right;  // 假设q为节点4

    TreeNode* ancestor = findLowestCommonAncestor(root, p, q);

    if (ancestor) {
        printf("节点 %d 和节点 %d 的最近公共祖先是节点 %d\n", p->data, q->data, ancestor->data);
    } else {
        printf("未找到节点 %d 和节点 %d 的最近公共祖先\n", p->data, q->data);
    }
    return 0;
}

2.非递归(未实现)

19.所有叶子节点带权路径和

typedef struct BitNode{
    int weight;
    struct BitNode *lchild,*rchild;
}BitNode,*BitTree;

int wpl(BitTree root){
    return  wpl_preorder(root,0);
}

int wpl_preorder(BitTree root,int deep){
    static int w1=0;
    if(root->lchild==NULL &&root->rchild ==NULL){
        w1+= deep* root->weight;
    }
    if(root->lchild!=NULL){
        wpl_preorder(root->lchild,deep+1);
    }
    if(root->rchild!=NULL){
        wpl_preorder(root->rchild,deep+1);
    }
    return w1;
}

20.字符计算转中缀并加括号

void Btree(Btree*root){
    BtreeTo(root,1);
}
void BtreeTo(Btree* root,int deep){
    if(root==NULL)
        return ;
    else if(root->left==NULL && root->right ==NULL)
        printf("%d",root->data);
    else{
        if(deep>1) printf("(");
        BtreeTo(root->left,deep+1);
        printf("%s",root->data);
        BtreeTo(root->right,deep+1);
        if(deep>1)printf(")");
    }
}

21.判断顺序存储的二叉树是否是二叉排序树

#include <stdio.h>
#include <stdlib.h>

int pre=0;
bool InOrder(SqBiTNode*bt,int i){
    if(bt->SqBiTNode[i] == -1)      //空节点符合
        return true;
    if(!InOrder(bt,2*i+1))          //递归左子树
        return false;               //左子树不符合 返回flase

    if(pre > bt->SqBiTNode[i])      // 如果前驱大于当前节点 不符合
        return false;

    pre=bt->SqBiTNode[i];           //更新前驱
    if(!InOrder(bt,2*i+2))          //递归右子树
        return false;

    return true;        //false都没返回ture
}



int main()
{
    printf("Hello world!\n");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值