数据结构—树(二叉树)

#define _CRT_SECURE_NO_WARNINGS 1


//树:非线性的数据结构,由有限个节点组成一个具有层次关系的集合。像是一颗倒挂的树,所以叫树。
//树的相关概念:
//1、节点的度:一个节点含有的子树的个数成为节点的度
//2、叶节点(终端节点):度为0的节点称为终端节点,(子节点为空的节点)
//3、非终端节点(分支节点):度不为0的节点,即(子节点不为空的节点)
//4、双亲节点(父节点):若一个节点含有子节点,称该节点为子节点的父节点
//5、孩子节点(子节点):一个节点含有的子树的根节点称为该节点的子节点
//6、兄弟节点:具有相同父节点的节点称为兄弟节点
//7、树的度:一棵树中,最大的节点的度称为树的度
//8、节点的层次:从根开始定义起,根为第一层,根的子节点为第二层,以此类推
//9、树的高度或深度:树中节点的最大层次
//10、堂兄弟节点:双亲在同一层的节点互为堂兄弟节点
//11、节点的祖先:从根到该节点所经分支上的所有节点
//12、子孙:以某节点为根的子树中的任一节点,都称为该节点的子孙
//13、森林:多棵不想交的树的集合称为森林
//
//
//树的每个节点又有子节点。没有父节点的节点称为根节点。每个非根节点有且只有一个父节点,每个子节点可以分成多个不相交的子树。
//
//树的存储方式有多种,如双亲表示法、孩子表示法、孩子兄弟表示法。
//1、双亲表示法:用连续的空间存储每个节点,每个节点中有一个指向双亲节点地址的指针。容易找到双亲节点,不易找到孩子节点。
//2、孩子表示法:将每个节点的孩子节点用链表链接起来,容易找到孩子节点,但是不容易找到双亲节点。
//3、孩子兄弟表示法:在每个节点中,保存一个指向自己第一个孩子节点的指针,还保存一个指针自己下一个兄弟节点的指针。
//
//树的应场景:人工智能中的决策树、MYSQL数据库索引、文件系统的目录结构等。
//
//二叉树:有限个节点集合,该集合为空,或者是由一个根节点加一棵左子树和一棵右子树组成的两个分支的树结构。
//二叉树的特点:每个节点最多有两棵子树,二叉树的两个子树分别称为左右子树,次序不能颠倒。
//五种基本形式:一个空节点、 只有一个非空节点、 根节点有一棵左子树、 根节点有一棵右子树、 根节点有左右子树
//
//满二叉树:每一层节点数都达到最大值的二叉树。(除了最后一层叶子节点,其它每个节点都有左右棵子树),层数为 K ,节点数为 (2^k-1)。
//完全二叉树:深度为 K ,有 n 个节点的二叉树,当且仅当其每一个节点都与深度为 K 的满二叉树中编号从1到 n 的节点一一对应。
//           (相同高度的完全二叉树叶子节点这一层,从最右边一个右往左依次缺失部分子树。)
//           (满二叉树是一种特殊的完全二叉树)
//二者的区别: 满二叉树的每一层,节点个数都达到最大值,也就是除了叶子节点那一层,每一层的父节点都有不为空的左右子树.
//            完全二叉树的最后一层的节点个数可能没有达到最大值。
//
//二叉树的顺序存与链式存储
//顺序存储:使用数组来存储,一般只适合用来表示完全二叉树,因为不是完全二叉树会有空节点造成空间浪费,现实中只有堆才会用数组存储。
//          二叉树顺序存储在物理上是数组,在逻辑上是二叉树。
//
//链式存储:用链表来表示二叉树,用链来指示元素的逻辑关系。通常的方法是链表中每个节点由数据域和左右指针域三部分组成。
//          数据域保存值,左右指针保存左右孩子节点的地址。
//
//二叉树有三种遍历方式:前序遍历、中序遍历、后序遍历
//
//实现二叉树以下操作。
// 1. 创建二叉树 
//BTNode* CreateBinTree(BTDataType* array, int size);
//
// 销毁二叉树 
//void DestroyTree(BTNode** pRoot);
//
// 二叉树的三种遍历方式 
//void PreOrder(BTNode* pRoot);
//void InOrder(BTNode* pRoot);
//void PostOrderNor(BTNode* pRoot);
//
//void LevelOrder(BTNode* pRoot);
//
// 获取二叉树中节点的个数 
//int GetNodeCount(BTNode* pRoot);
//
// 求二叉树的高度 
//int Height(BTNode* pRoot);
//
// 获取二叉数中叶子节点的个数 
//int GetLeafNodeCount(BTNode* pRoot);
//
// 获取二叉树第K层节点的个数 
//int GetKLevelNodeCount(BTNode* pRoot, int K);
//
// 获取二叉树中某个节点的双亲节点 
//BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode);


#pragma once

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

typedef struct Node {
    int  value;
    struct Node *left;    // 指向左孩子节点
    struct Node *right;    // 指向右孩子节点
}    Node;


// 前序遍历
void preOrderTraversal(Node *root) 
{
    if (root == NULL)
    {
        return;
    }
    printf("%d ", root->value);
    preOrderTraversal(root->left);
    preOrderTraversal(root->right);
}

// 中序遍历
void inOrderTraversal(Node *root) 
{
    if (root == NULL)
    {
        return;
    }
    inOrderTraversal(root->left);
    printf("%d ", root->value);
    inOrderTraversal(root->right);
}


 //后序遍历
void postOrderTraversal(Node *root) 
{
    if (root == NULL) 
    {
        return;
    }
    postOrderTraversal(root->left);
    postOrderTraversal(root->right);
    printf("%d ", root->value);
}



//通过中序遍历来实现节点个数统计
 int count = 0;
void getNodeCount(Node *root)
{
    if (root == NULL)
    {
        return;
    }

    getNodeCount(root->left);
    count++;
    getNodeCount(root->right);
}

//通过后序遍历来实现节点个数统计
int getNodeCount2(Node *root)
{
    if (root == NULL)
    {
        return 0;
    }

    int left = getNodeCount2(root->left);
    int right = getNodeCount2(root->right);

    return left + 1 + right;
}

int myMax(int a, int b) 
{
    return a >= b ? a : b;
}

//获取二叉树的高度
int getHeight(Node *root) 
{
    if (root == NULL) 
    {
        return 0;
    }
    //分别对获取左右子树的高度,然后返回最大的值
    int left = getHeight(root->left);
    int right = getHeight(root->right);

    return left >= right ? left : right;
    //返回值封装成函数
    return myMax(left, right) + 1;
    
}

//统计叶子节点的个数
int getLeafCount(Node *root)
{
    if (root == NULL)
    {
        return 0;
    }
    //每找到一个节点,它的左右子树都是空节点时返回一个1
    else if (root->left == NULL && root->right == NULL) 
    {
        return 1;
    }
    else 
    {
        //递归分别对左子树和右子树的叶子节点进行统计
        return getLeafCount(root->left) + getLeafCount(root->right);
    }
}

//k层节点个数
int getKLevelCount(Node *root, int k) 
{
    assert(k >= 1);

    if (root == NULL) 
    {
        return 0;
    }
    else if (k == 1) 
    {
        return 1;
    }
    else 
    {
        return getKLevelCount(root->left, k - 1)
            + getKLevelCount(root->right, k - 1);
    }
}

//二叉树中查找指定值
Node * find(Node *root, int v)
{
    if (root == NULL) 
    {
        return NULL;    // 没有找到
    }

    if (root->value == v) 
    {
        return root;
    }

    Node * left = find(root->left, v);
    if (left != NULL) 
    {
        return left;
    }

    Node * right = find(root->right, v);
    if (right != NULL) 
    {
        return right;
    }
    else
    {
        return NULL;
    }
}


//销毁二叉树

void DestroyTree(Node *node)
{
    Node *head = NULL;
    Node *prev = NULL;
    node->left = prev;
    if (prev == NULL) 
    {
        head = node;
    }
    else 
    {
        prev->right = node;
    }

    prev = node;
}

//创建树
Node * createTree(int *arr, int size)
{
//将数组中的值放到节点中
    Node *n1 = (Node *)malloc(sizeof(Node));
    n1->value = arr[0];
    Node *n2 = (Node *)malloc(sizeof(Node));
    n2->value = arr[1];
    Node *n3 = (Node *)malloc(sizeof(Node));
    n3->value = arr[2];
    Node *n4 = (Node *)malloc(sizeof(Node));
    n4->value = arr[3];
    Node *n5 = (Node *)malloc(sizeof(Node));
    n5->value = arr[4];
    Node *n6 = (Node *)malloc(sizeof(Node));
    n6->value = arr[5];
    Node *n7 = (Node *)malloc(sizeof(Node));
    n7->value = arr[6];
    Node *n8 = (Node *)malloc(sizeof(Node));
    n8->value = arr[7];
  //将节点链接成树
    n1->left = n2; n1->right = n3;
    n2->left = n4; n2->right = n5;
    n3->left = n6; n3->right = n7;
    n4->left = NULL; n4->right = NULL;
    n5->left = NULL; n5->right = n8;
    n6->left = NULL; n6->right = NULL;
    n7->left = NULL; n7->right = NULL;

    return n1;
}


int main()
{
    int arr[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    int size = sizeof(arr) / sizeof(arr[0]);

    //创建树
    Node* n1=createTree(arr, size);

    // 1 2 3 4 5 6 7 8
    // a b c d e f g h
    //递归方式实现三种遍历。通过打印值来看遍历的顺序
    preOrderTraversal(n1); printf("\n"); //1 2 4 5 8 3 6 7
    inOrderTraversal(n1); printf("\n");  //4 2 5 8 1 6 3 7
    postOrderTraversal(n1); printf("\n");//4 8 5 2 6 7 3 1

    system("pause");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fengkun/p/11253508.html