二叉树的链式结构和遍历


在这里插入图片描述

普通二叉树增删查改没有价值,如果是为了单纯的存储数据,不如用线性表
只是为了更好的控制他的结构,为后续学习更复杂的搜索二叉树打基础

typedef int BTDatatype;
typedef struct BinaryTreeNode
{
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* left;
}BTNode;
BTNode* BuyNode(BTDatatype x)
{
    BTNode* node=(BTNode*)malloc(sizeof(BTNode));
    if(node==NULL)
    {
        printf("malloc fail");
        exit(-1);
    }
    node->left=node->right=NULL;
    node->data=x;
    return node;
}
//创建树
BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);
	node1->_left = node2;
	node1->_right = node4;
	node2->_left = node3;
	node4->_left = node5;
	node4->_right = node6;
	return node1;
}

image-20220409092204337
在这里插入图片描述

1.树的遍历

以下面的这棵树为例子

image-20220409093541365

1.1.前序遍历(先根遍历)

根 左子树 右子树

1 2 3 NULL NULL NULL 4 5 NULL NULL 6 NULL NULL

void PreOrder(BTNode* root)
{
    if(root==NULL)
    {
        printf("NULL ");
		return ;
    }
    printf("%d ",root->data);
    PreOrder(root->letf);
    PreOrder(root->right);
}
1.2.中序遍历(中根遍历)

左子树 根 右子树

NULL 3 NULL 2 NULL 1 NULL 5 NULL 4 NULL 6 NULL

void InOrder(BTNode* root)
{
    if(root==NULL)
    {
        printf("NULL ");
        return ;
    }
    InOrder(root->letf);
    printf("%d ",root->data);
    InOrder(root->right); 
}
1.3.后序遍历(后根遍历)

左子树 右子树 根

NULL NULL 3 NULL 2 NULL NULL 5 NULL NULL 6 4 1

void PostOrder(BTNode* root)
{
    if(root==NULL)
    {
        printf("NULL ");
        return ;
    }
    PostOrder(root->letf);
    PostOrder(root->right); 
    Postprintf("%d ",root->data);
}
1.4.层序遍历

1 2 4 3 NULL 5 6 NULL NULL NULL NULL

//层序遍历,使用队列实现,把节点依次放入队列中
void BinaryTreeLevelOrder(BTNode* root)
{
    //创建一个队列
	Queue qu;
    //初始化
	QueueInit(&q);
    if(root)
    {
        QueuePush(&q,root);
    }
    while(!QueueEmpty(&q))
    {
        BTNode*front=QueueFront(&q);
        QueuePop(&q);
        printf("%d ",front->data);
        if(root->left)
        {
            QueuePush(&q,front->left);
        }
        if(root->right)
        {
            QueuePush(&q,front->right);
        }
    }
    printf("\n");
    QueueDestory(&q);
}
1.5.二叉树的常见问题

树中的结点个数

//方法一
int BTreeSize(NTNode* root)
{
    //三目操作符
    return root==NULL?0:Prenum(root->left)+Prenum(root->right)+1
}
//方法二
void BTreeSize(BTNode* root,int*count)
{
    if(root==NULL)
        return 0;
    *count++; 
    BTreeSize(root->left,count);
    BTreeSize(root->right,count);
}
int num=0;
int*count=#
BTreeSize(root,count);

二叉树叶子节点个数

int BTreeleafSize(BTNode* root)
{
    //首先不是空
    if(root==NULL)
    {
        return 0;
    }
    //而且左子树是空和右子树是空
	if(root->left==NULL&&root->right==NULL)
    {
        return 1;
    }
    return BTreeleafSize(root->left)+BTreeleafSize(root->right);
}

二叉树第k层节点个数

image-20220409120232623

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL || k < 0)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

求二叉树的高度

int BTreeDepth(BTNode*root)
{
    if(root==NULL)
        return 0;
    int leftDepth=BTreeDepth(root->left);
    int rightDepth=BTreeDepth(root->right);
    return leftDepth>rightDepth?leftDepth+1:rightDepth+1;
}

二叉树查找值为x的节点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    if(root==NULL)
        return NULL;
    if(x==root->data)
    {
        return root;
    }
    else
    {   
        //先去找左边的子树
        BTNode*tmp=NULL;
    	tmp=BinaryTreeFind(root->left,x);
        //如果没有在左子树
    	if(tmp==NULL)
        {
           //找右子树
            return BinaryTreeFind(root->right,x);
        }
        //如果有,就返回
        return tmp;
    }
    //如果找不到,返回NULL
    return NULL;
}

找祖先节点

int putRootfx(BTNode* root, BTDataType x)
{
    if(root==NULL)
        return 0;
    if(root->data==x)
    {	
        printf("%d ",root->data);
        return 1;
    }
    if(root)
    {
        if(putRootfx(root->left,x)||putRootfx(root->right,x))
        {
            printf("%d ",root->data);
            return 1;
        }
    }
    return 0;
}

判断二叉树是否是完全二叉树*[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UW8YFvqy-1650035166002)(C:/Users/%E5%88%98%E9%91%AB/AppData/Roaming/Typora/typora-user-images/image-20220415201641493.png)]

int BinaryTreeComplete(BTNode* root)
{
    //创建一个队列
	Queue q;
    QueueInit(&q,root);
    if(root)
        QueuePush(&q,root);
    while(!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
		QueuePop(&q);
        //如果是空,跳出循环,判断后面的是不是空
		if (front == NULL)
			break;
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
    }
    while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		// 空后面出到非空,那么说明不是完全二叉树
		if (front)
		{
			QueueDestory(&q);
			return false;
		}
	}

	QueueDestory(&q);
	return true;
}

在这里插入图片描述

2.二叉树的练习题

题目一

image-20220411005244328

#define MAX_NUM 1001
int* levelOrder(struct TreeNode* root, int* returnSize){
    *returnSize=0;
    if(root==NULL)
        return NULL;
    int*ans=(int*)malloc(sizeof(int)*MAX_NUM);
    //队列
    struct TreeNode*tree[MAX_NUM];
    memset(tree,0,sizeof(struct TreeNode*));
    int head=0;
    int tail=0;
    tree[tail++]=root;//存入根结点
    while(head<tail)
    {
        //开始遍历
        struct TreeNode*tmp=tree[head++];
        ans[(*returnSize)++] = tmp->val;
        if(tmp->left!=NULL)
        {
            tree[tail++]=tmp->left;
        }
        if(tmp->right!=NULL)
        {
            tree[tail++]=tmp->right;
        }
    }
    return ans;
}

题目二

image-20220411012116897

//用一个队列来输出每一层的节点,在用一个二维数组来记录每一层的节点
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
    if(root == NULL){
        (*returnSize)= 0;
        return root;
    }

    struct TreeNode* queue[1010];
    int front = 0, rear = 0, i = 0, j = 0, count = 0, k = 1;
    struct TreeNode* p = NULL;
    int** array = (int**)malloc(sizeof(int*)*1010);//申请一个指针数组(二维数组)
    *returnColumnSizes = (int*)malloc(sizeof(int)*1010);//申请一个int型数组
    queue[rear++] = root;//入队列
    array[i] = (int*)malloc(sizeof(int)*k);//用指针数组的第一个指针指向树第一层的数组
    (*returnColumnSizes)[i] = k;//第一层数组的长度
    while(front < rear){
        p = queue[front++];//出队列并用指针p指向该节点
        array[i][j++] = p->val;//二维数组第i层第j个元素记录该节点的值
        if(p->left){//查看左孩子,有则入队
            queue[rear++] = p->left;
            count++;//记录下一层节点数
        }
        if(p->right){//查看右孩子,有则入队
            queue[rear++] = p->right;
            count++;
        }
        k--;//改层已经记录一个节点值,若k==0,则说明该层的节点已经记录完,用k=count,来更新下一层节点数
        if(k == 0){
            k = count;
            count = 0;
            j = 0;//从当前i层第一个节点开始,所以对应当前二维数组第i行第一个元素
            i++;//到下一层,也到下一行
            array[i] = (int*)malloc(sizeof(int)*k);//重新分配下一层对应节点的数组大小
            (*returnColumnSizes)[i] = k;//返回下一层节点个数
        }
    }
        *returnSize = i;
    return array;
}
///
///

 #define N 1010
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
    if(root==NULL)
    {
        *returnSize=0;
        return NULL;
    }   
    struct TreeNode* queue[N];
    //开二维数组存放一维数组的指针
    int**array=(int**)malloc(sizeof(int*)*N);
    *returnColumnSizes=(int*)malloc(sizeof(int*)*N);
    //k用来记录存放了多少个数据
    int head=0,tail=0,i=0,j=0,k=1,count=0;
    queue[tail++]=root;
    //第一层的结点数为1个
    (*returnColumnSizes)[i]=k;
    //开辟存放数据数组
    array[i]=(int*)malloc(sizeof(int)*k);
    while(head<tail)
    {
        struct TreeNode*tmp=queue[head++];
        array[i][j++]=tmp->val;
        if(tmp->left)
        {
            queue[tail++]=tmp->left;
            //记录下一层需要遍历的个数
            count++;
        }
        if(tmp->right)
        {
            queue[tail++]=tmp->right;
            //记录下一场需要遍历的个数
            count++;
        }
        //如果该层的结点全部被遍历一遍,就进行下一步
        k--;
        if(k==0)
        {
            //下一层需要遍历的结点数;
            k=count;
            j=0;
            count=0;
            i++;
            (*returnColumnSizes)[i]=k;
            array[i]=(int*)malloc(sizeof(int)*k);
        }
    }
    //返回多少层
    *returnSize=i;
    return array;
}

题目三

image-20220411090028254

 //反转数组 
#define N 1010
void reverse(int**arr,int k,int len)
{
    int left=0;
    int right=len-1;
    while(left<right)
    {
        int tmp=arr[k][left];
        arr[k][left]=arr[k][right];
        arr[k][right]=tmp;
        left++;
        right--;
    }
}  
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
    if(root==NULL)
    {
        *returnSize=0;
        return NULL;
    }
   //开辟存放一级指针的数组
    int**array=(int**)malloc(sizeof(int*)*N);
    //开辟存放数组长度的数组
    *returnColumnSizes=(int*)malloc(sizeof(int)*N);
    //创建一个队列
    struct TreeNode* queue[N];
    memset(queue,0,sizeof(struct TreeNode*));
    int head=0,tail=0,i=0,j=0,count=0,k=1;
    (*returnColumnSizes)[i]=k;
    queue[tail++]=root;
    array[i]=(int*)malloc(sizeof(int)*k);
    while(head<tail)
    {
        struct TreeNode*tmp=queue[head++];
        array[i][j++]=tmp->val;
        if(tmp->left)
        {
            queue[tail++]=tmp->left;
            count++;
        }
        if(tmp->right)
        {
            queue[tail++]=tmp->right;
            count++;
        }
        //记录剩下还没有打印的结点
        k--;
        if(k==0)
        {
            j=0;
            i++;
            k=count;
            count=0;
            array[i]=(int*)malloc(sizeof(int)*k);
            (*returnColumnSizes)[i]=k;
            if(i%2==0)
            {
                reverse(array,i-1,(*returnColumnSizes)[i-1]);
            }
        }

    }
    *returnSize=i;
    return array;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
// BTree.cpp : Defines the entry point for the console application. /* 作者:成晓旭 时间:2001年7月2日(9:00:00-14:00:00) 内容:完成二叉树的创建、前序遍历、中序遍历、后序遍历 时间:2001年7月2日(14:00:00-16:00:00) 内容:完成二叉树的叶子节点访问,交换左、右孩子 */ #include "stdafx.h" #include "stdlib.h" #define MAX_NODE 100 #define NODE_COUNT1 8 #define NODE_COUNT2 15 int TreeValue0[NODE_COUNT1][2] = {{'0',0},{'D',1},{'B',2},{'F',3},{'A',4},{'C',5},{'E',6},{'G',7}}; int TreeValue1[NODE_COUNT1][2] = {{'0',0},{'A',1},{'B',2},{'C',3},{'D',4},{'E',5},{'F',6},{'G',7}}; int TreeValue2[NODE_COUNT2][2] = {{'0',0},{'A',1},{'B',2},{'C',3},{'D',4},{'E',5},{'F',6},{'G',7},{'H',8},{'I',9},{'J',10},{'K',11},{'L',12},{'M',13},{'N',14}}; struct BTree { int data; int order; BTree *lchild; BTree *rchild; }; void Swap(int *p1,int *p2) { int t; t = *p1; *p1 = *p2; *p2 = t; } /* function CreateBTree()功能:创建一颗二叉树,并返回一个指向其根的指针 */ BTree *CreateBTree(int data[][2],int n) { BTree *Addr[MAX_NODE]; BTree *p, *head; int nodeorder,//节点序号 noderoot, //节点的双亲 i; if(n>MAX_NODE) { printf("参数错误!\n"); return(0); } for(i=1;i<=n;i++) { p = (BTree *)malloc(sizeof(BTree)); if(p==NULL) { printf("内存溢出错误!\n"); return(0); } else { p->data = data[i][0]; p->lchild = NULL; p->rchild = NULL; nodeorder = data[i][1]; p->order = nodeorder; Addr[nodeorder] = p; if(nodeorder>1) { noderoot = nodeorder/2; if(nodeorder %2 == 0) Addr[noderoot]->lchild = p; else Addr[noderoot]->rchild = p; } else head = p; printf("BTree[%d] = %c\t",p->order,p->data); } //free(p); } return(head); } /* function FirstOrderAccess0()功能:实现二叉树的前序遍历 二叉树前序遍历的思想: 从根节点开始,沿左子树一直走到没有左孩子的节点为止, 依次访问所经过的节点,同时所经[节点]的地址进栈; 当找到没有左孩子的节点时,从栈顶退出该节点的双亲的 右孩子,此时,此节点的左子树已访问完毕; 在用上述方法遍历该节点的右子树,如此重复到栈空为止。 */ void FirstOrderAccess0(BTree * header) { BTree * stack[MAX_NODE]; BTree *p; int top; top = 0; p = header; do { while(p!=NULL) { printf("BTree[%d] = %c\t",p->order,p->data);//访问节点P top = top+1; stack[top] = p; p = p->lchild;//继续搜索节点P的左子树 } if(top!=0) { p = stack[top]; top = top-1; p = p->rchild;//继续搜索节点P的右子树 } }while((top!=0)||(p!=NULL)); } /* function FirstOrderAccess1()功能:实现二叉树的前序遍历 二叉树前序遍历的思想: 从根节点开始,沿左子树一直走到没有左孩子的节点为止, 依次访问所经过的节点,同时所经[节点的非空右孩子]进栈; 当找到没有左孩子的节点时,从栈顶退出该节点的双亲的 右孩子,此时,此节点的左子树已访问完毕; 在用上述方法遍历该节点的右子树,如此重复到栈空为止。 */ void FirstOrderAccess1(BTree * header) { BTree * stack[MAX_NODE]; BTree *p; int top; top = 0; p = header; do { while(p!=NULL) { printf("BTree[%d] = %c\t",p->order,p->data); if(p->rchild!=NULL) stack[++top] = p->rchild; p = p->lchild; } if(top!=0) p = stack[top--]; }while((top>0)||(p!=NULL)); } /* function MiddleOrderAccess()功能:实现二叉树的中序遍历 二叉树中序遍历的思想: 从根节点开始,沿左子树一直走到没有左孩子的节点为止, 并将所经[节点]的地址进栈; 当找到没有左孩子的节点时,从栈顶退出该节点并访问它, 此时,此节点的左子树已访问完毕; 在用上述方法遍历该节点的右子树,如此重复到栈空为止。 */ void MiddleOrderAccess(BTree * header) { BTree * stack[MAX_NODE]; BTree *p; int top; top = 0; p = header; do { while(p!=NULL) { stack[++top] = p;//节点P进栈 p = p->lchild; //继续搜索其左子树 } if(top!=0) { p = stack[top--];//节点P出栈 printf("BTree[%d] = %c\t",p->order,p->data);//访问节点P p = p->rchild;//继续搜索其左子树 } }while((top!=0)||(p!=NULL)); } /* function LastOrderAccess()功能:实现二叉树的后序遍历 二叉树后序遍历的思想: 从根节点开始,沿左子树一直走到没有左孩子的节点为止, 并将所经[节点]的地址第一次进栈; 当找到没有左孩子的节点时,此节点的左子树已访问完毕; 从栈顶退出该节点,判断该节点是否为第一次进栈,如是,再 将所经[节点]的地址第二次进栈,并沿该节点的右子树一直走到 没有右孩子的节点为止,如否,则访问该节点;此时,该节点的 左、右子树都已完全遍历,且令指针p = NULL; 如此重复到栈空为止。 */ void LastOrderAccess(BTree * header) { BTree * stack[MAX_NODE];//节点的指针栈 int count[MAX_NODE];//节点进栈次数数组 BTree *p; int top; top = 0; p = header; do { while(p!=NULL) { stack[++top] = p;//节点P首次进栈 count[top] = 0; p = p->lchild; //继续搜索节点P的左子树 } p = stack[top--];//节点P出栈 if(count[top+1]==0) { stack[++top] = p;//节点P首次进栈 count[top] = 1; p = p->rchild; //继续搜索节点P的左子树 } else { printf("BTree[%d] = %c\t",p->order,p->data);//访问节点P p = NULL; } }while((top>0)); } /* function IsLeafNode()功能:判断给定二叉树的节点是否是叶子节点 */ int IsLeafNode(BTree *node) { if((node->lchild==NULL)&&(node->rchild==NULL)) return(1); else return(0); } /* function PrintLeafNode()功能:输出给定二叉树的叶子节点 */ void PrintLeafNode(BTree *header) { BTree * stack[MAX_NODE];//节点的指针栈 BTree *p; int top; p = header; top = 0; do { while(p!=NULL) { stack[++top] = p; p = p->lchild;//继续搜索节点P的左子树 } if(top!=0) { p = stack[top--]; if(IsLeafNode(p)) printf("LNode[%d] = %c\t",p->order,p->data);//访问叶子节点 p = p->rchild;//继续搜索节点P的右子树 } }while(top>0||p!=NULL); } /* function HasTwoChildNode()功能:判断给定二叉树的节点是否存在两个孩子节点 */ int HasTwoChildNode(BTree *node) { if((node->lchild!=NULL)&&(node->rchild!=NULL)) return(1); else return(0); } /* function SwapChildNode()功能:交换给定二叉树的所有节点的左、右孩子 */ void SwapChildNode(BTree *header) { BTree * stack[MAX_NODE];//节点的指针栈 BTree *p; int top; p = header; top = 0; do { while(p!=NULL) { stack[++top] = p; p = p->lchild;//继续搜索节点P的左子树 } if(top!=0) { p = stack[top--]; if(HasTwoChildNode(p)) Swap(&p->lchild->data,&p->rchild->data);//交换节点P的左、右孩子 p = p->rchild;//继续搜索节点P的右子树 } }while(top>0||p!=NULL); } int main(int argc, char* argv[]) { BTree * TreeHeader; printf("二叉树创建数据结果:\n"); TreeHeader = CreateBTree(TreeValue1,NODE_COUNT1-1); //TreeHeader = CreateBTree(TreeValue2,NODE_COUNT2-1); if (TreeHeader==0) { printf("二叉树创建失败!\n"); return(0); } else { printf("\n二叉树前序遍历结果:\n"); FirstOrderAccess1(TreeHeader); printf("\n二叉树中序遍历结果:\n"); MiddleOrderAccess(TreeHeader); printf("\n二叉树后序遍历结果:\n"); LastOrderAccess(TreeHeader); //printf("\n二叉树的所有叶子节点:\n"); //PrintLeafNode(TreeHeader); //SwapChildNode(TreeHeader); //printf("\n二叉树交换孩子的结果:\n"); //MiddleOrderAccess(TreeHeader); printf("\n程序运行完毕!\n"); return 0; } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

影中人lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值