1. 程式人生 > >二叉樹(一)

二叉樹(一)

二叉樹的基本概念

  • 什麼是二叉樹

一棵二叉樹是結點的一個有限集合,該集合或者為空,或者是由一個根節點加上兩棵分別稱為左子樹和右子樹的二叉樹組成

  • 特點

每個結點最多有兩棵子樹,即二叉樹不存在度大於2的結點

二叉樹的子樹有左右之分,其子樹的次序不能顛倒

avater

  • 兩種特殊的二叉樹
  1. 滿二叉樹:在一棵二叉樹中,如果所有分支結點都存在左子樹和右子樹,並且所有葉子節點都在同一層上
  2. 完全二叉樹:如果一棵具有N個結點的二叉樹的結構與滿二叉樹的前N個結點的結構相同,稱為完全二叉樹

avater

二叉樹的性質

若規定根節點的層數為1,則一棵非空二叉樹的第i層上最多有(i>0)個結點

若規定只有根節點的二叉樹的深度為1,則深度為K的二叉樹的最大結點數是(k>=0)

對任何一棵二叉樹, 如果其葉結點個數為 n0,度為2的非葉結點個數為 n2,則有n0=n2+1

具有n個結點的完全二叉樹的深度k為log(n+1)上取整

對於具有n個結點的完全二叉樹,如果按照從上至下從左至右的順序對所有節點從0開始編號,則對於序號為i的結點有:

  1. 若i>0,雙親序號:(i-1)/2;i=0,i為根節點編號,無雙親結點
  2. 若2i+1<n,左孩子序號:2i+1,否則無左孩子
  3. 若2i+2<n,右孩子序號:2i+2,否則無右孩子
  • 二叉樹的基本操作

  •  二叉樹的儲存結構

typedef int TDataType;

typedef struct BTreeNode
{
	TDataType data;
	struct BTreeNode* left;
	struct BTreeNode* right;
} BTreeNode;

//建立節點
BTreeNode* CreateNode(TDataType data)
{
	BTreeNode* newNode = (BTreeNode*)malloc(sizeof(BTreeNode));
	newNode->data = data;
	newNode->left = newNode->right = NULL;

	return newNode;
}
  •  建立一個二叉樹

avater

BTreeNode * CreateTree(int preOrder[], int size, int *pUsedSize)
{
    int leftUse, rightUse;
	int rootValue = preOrder[0];
    //元素已經沒有剩餘了
    if(size <= 0)
    {
        *pUsedSize = 0;
        return NULL;
    }
    //空節點
    if (rootValue == -1)
	{
		*pUsedSize = 1;
		return NULL;
	}
	BTreeNode* root = CreateNode(rootValue);

	root->left = CreateTree(preOrder + 1, size - 1, &leftUse);
	root->right = CreateTree(preOrder + 1 + leftUse, size - 1 - leftUse, &rightUse);
    //實際的使用情況
	*pUsedSize = 1 + leftUse + rightUse;

	return root;
}
  •  前序、中序、後序的遍歷(遞迴)
//前序遍歷
void PreOrder(BTreeNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}
//中序遍歷
void InOrder(BTreeNode *root)
{
	if (root == NULL) 
	{
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}
//後序遍歷
void PostOrder(BTreeNode *root)
{
	if (root == NULL) 
	{
		return; 
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

  •  前序、中序、後序遍歷(非遞迴)

avater

 

/*
非遞迴的方式我們需要用到棧的知識,
但是因為我們壓棧,棧裡面儲存的是節點地址,
所以要對之前的棧的操作進行修改

struct BTreeNode;
//將原本的int型別改成BTreeNode*
typedef struct BTreeNode* StackDataType;
*/
#include "Stack.h"

void PreOrderLoop(BTreeNode *root)
{
    Stack stack;
	StackInit(&stack);
	BTreeNode *cur;
	cur = root;
	BTreeNode *top;
	if (root == NULL)
	{
		return;
	}
	while (cur != NULL || !StackEmpty(&stack))
	{
		while (cur != NULL)
		{
			printf("%d ", cur->data);
			StackPush(&stack, cur);
			cur = cur->left;
		}
		
		top = StackTop(&stack);
		StackPop(&stack);
		
		cur = top->right;
	}
}

void InOrderLoop(BTreeNode *root)
{
	Stack stack;
	StackInit(&stack);
	BTreeNode *cur = root;
	BTreeNode *top;
	if (root == NULL)
	{
		return;
	}

	while (cur != NULL || !StackEmpty(&stack))
	{
		while (cur != NULL)
		{
			StackPush(&stack, cur);
			cur = cur->left;
		}
		top = StackTop(&stack);
		StackPop(&stack);
		printf("%d ", top->data);
		cur = top->right;
	}
}

void PostOrderLoop(BTreeNode *root)
{
	Stack stack;
	StackInit(&stack);
	BTreeNode *cur = root;
	BTreeNode *top;
	BTreeNode *last = NULL;

	while (cur != NULL || !StackEmpty(&stack))
	{
		while (cur != NULL)
		{
			StackPush(&stack, cur);
			cur = cur->left;
		}
		top = StackTop(&stack);
		
		if(top->right == NULL || top->right == last)
		{
			StackPop(&stack);
			printf("%d ", top->data);
			last = top;
		}
		else
		{
			cur = top->right;
		}
	}

}