1. 程式人生 > >二叉樹的基本操作 C語言

二叉樹的基本操作 C語言

                            二叉樹的各項基本操作C語言

struct tree_node{
	char id;
	struct tree_node *left;
	struct tree_node *right;
};

typedef struct tree_node TreeNode;
typedef struct tree_node *Tree;

下面的描述都用下圖所示的這棵二叉樹為例。

1、二叉樹的遍歷

二叉樹的遍歷有四種方式:前序遍歷、中序遍歷、後序遍歷、層序遍歷。

1.1、前序遍歷

先訪問根節點,再分別前序遍歷左、右兩棵子樹。前序遍歷的結果是:ABCDEF

程式碼以遞迴方式實現:

//前序遍歷
void PreShow(Tree T)
{
	if (!T)
	{
		return;
	}
	
	printf("%c ", T->id);
	PreShow(T->left);
	PreShow(T->right);
}

1.2、中序遍歷

先中序遍歷左子樹,然後訪問根節點,最後中序遍歷右子樹。中序遍歷的結果是:CBAEDF

//中序遍歷
void MidShow(Tree T)
{
	if (!T)
	{
		return;
	}
	
	MidShow(T->left);
	printf("%c ", T->id);
	MidShow(T->right);
}

1.3、後序遍歷

先後序遍歷左子樹,再後序遍歷右子樹,最後訪問根節點。後序遍歷的結果是:CBEFDA

//後序遍歷
void BackShow(Tree T)
{
	if (!T)
	{
		return;
	}
	
	BackShow(T->left);
	BackShow(T->right);
	printf("%c ", T->id);
}

1.4、層序遍歷

從根節點開始,逐層訪問各子節點。層序遍歷的結果是:ABDCEF

前、中、後序遍歷都採用遞迴的方式,實際上也就是用到了棧。而層序遍歷則用佇列的方式實現,具體的步驟如下:

(1)初始化一個佇列,二叉樹的根節點進隊,即插入隊尾。

(2)隊首的樹節點出隊,訪問這個樹節點。先看它有沒有左孩子,如果有,就讓左孩子進隊。再看它有沒有右孩子,如果有,就讓右孩子也進隊。

(3)重複過程(2),直到佇列清空為止。

//層序遍歷
void LevelShow(Tree T)
{
	if (!T)
	{
		return;
	}

	Queue m_queue;
	Queue *Q;
	QueueNode *p, *q;

	Q = &m_queue;
	InitQueue(Q); //佇列初始化

	p = (QueueNode *)malloc(sizeof(QueueNode));
	p->next = NULL;
	p->treenode = T;
	InQueue(Q, p); //根節點進隊

	while (!IsQueueEmpty(Q))
	{
		OutQueue(Q, &q); //當前隊首節點出隊
		printf("%c ", q->treenode->id);

		if (q->treenode->left) //左孩子非空,則左孩子進隊
		{
			p = (QueueNode *)malloc(sizeof(QueueNode));
			p->next = NULL;
			p->treenode = q->treenode->left;
			InQueue(Q, p);
		}
		if (q->treenode->right) //右孩子非空,則右孩子進隊
		{
			p = (QueueNode *)malloc(sizeof(QueueNode));
			p->next = NULL;
			p->treenode = q->treenode->right;
			InQueue(Q, p);
		}
	}
}

2、二叉樹的生成

我採用輸入前序序列的方式生成二叉樹,但這裡的前序序列並不等同於前序遍歷。因為計算機需要知道哪些節點是空白節點,所以應該按下圖的方式輸入前序序列。


用*代表空白的節點,於是輸入的前序序列是:ABC***DE**F**

//建立二叉樹
void CreateTree(Tree *T)
{
	char ch;

	scanf("%c", &ch);
	if (ch == '*')
	{
		*T = NULL;
	}
	else
	{
		*T = (Tree)malloc(sizeof(TreeNode));
		(*T)->id = ch;
		CreateTree(&(*T)->left);
		CreateTree(&(*T)->right);
	}
}

3、二叉樹的刪除

先刪除左子樹,再刪除右子樹,最後刪除根節點,採用遞迴實現。

//清除二叉樹
void ClearTree(Tree *T)
{
	if (!*T)
	{
		return;
	}

	ClearTree(&(*T)->left);
	ClearTree(&(*T)->right);
	free(*T);
	*T = NULL;
}

4、獲得二叉樹的高度

如果二叉樹只有根節點,那麼它的高度就為1。否則二叉樹的高度等於1+左、右子樹高度的較大者。按這種方法遞迴實現。

//獲得二叉樹的高度
int GetHeight(Tree T)
{
	if (T)
	{
		return MaxOfTwo(GetHeight(T->left), GetHeight(T->right)) + 1;
	} 
	else
	{
		return 0;
	}
}

//兩數較大值
int MaxOfTwo(int a, int b)
{
	if (a >= b)
	{
		return a;
	} 
	else
	{
		return b;
	}
}

5、獲得二叉樹的節點數

二叉樹的節點數 = 左子樹節點數 + 右子樹的節點數 + 1。遞迴實現即可。

//獲得二叉樹的節點數
int GetNodeNumber(Tree T)
{
	if (T)
	{
		return GetNodeNumber(T->left) + GetNodeNumber(T->right) + 1;
	} 
	else
	{
		return 0;
	}
}

6、執行結果

輸入前序序列後,會顯示二叉樹的高度、節點數、四種遍歷的結果,最後刪除二叉樹。


7、完整程式碼

完整的程式碼如下:

#include <STDIO.H>
#include <STDLIB.H>

struct tree_node{
	char id;
	struct tree_node *left;
	struct tree_node *right;
};

struct queue_node{
	struct tree_node *treenode;
	struct queue_node *next;
};

struct queue{
	struct queue_node *front;
	struct queue_node *rear;
};

typedef struct tree_node TreeNode;
typedef struct tree_node *Tree;
typedef struct queue_node QueueNode;
typedef struct queue Queue;

void CreateTree(Tree *);
int GetHeight(Tree);
int MaxOfTwo(int, int);
int GetNodeNumber(Tree);
void PreShow(Tree);
void MidShow(Tree);
void BackShow(Tree);
void LevelShow(Tree);
void InitQueue(Queue *);
bool IsQueueEmpty(Queue *);
void InQueue(Queue *, QueueNode *);
void OutQueue(Queue *, QueueNode **);
void ClearTree(Tree *);
bool IsTreeEmpty(Tree);

int main(void)
{
	Tree t;

	printf("輸入二叉樹的前序遍歷序列,用*代替空節點:\n");
	CreateTree(&t);
	
	printf("\n二叉樹建立完畢,高度為%d,節點數為%d。", GetHeight(t), GetNodeNumber(t));
	
	printf("\n\n前序遍歷:");
	PreShow(t);
	
	printf("\n\n中序遍歷:");
	MidShow(t);
	
	printf("\n\n後序遍歷:");
	BackShow(t);
	
	printf("\n\n層序遍歷:");
	LevelShow(t);
	
	ClearTree(&t);
	if (IsTreeEmpty(t))
	{
		printf("\n\n二叉樹已經刪除。");
	}
	printf("\n\n");
	
	return 0;
}

//建立二叉樹
void CreateTree(Tree *T)
{
	char ch;

	scanf("%c", &ch);
	if (ch == '*')
	{
		*T = NULL;
	}
	else
	{
		*T = (Tree)malloc(sizeof(TreeNode));
		(*T)->id = ch;
		CreateTree(&(*T)->left);
		CreateTree(&(*T)->right);
	}
}

//獲得二叉樹的高度
int GetHeight(Tree T)
{
	if (T)
	{
		return MaxOfTwo(GetHeight(T->left), GetHeight(T->right)) + 1;
	} 
	else
	{
		return 0;
	}
}

//兩數較大值
int MaxOfTwo(int a, int b)
{
	if (a >= b)
	{
		return a;
	} 
	else
	{
		return b;
	}
}

//獲得二叉樹的節點數
int GetNodeNumber(Tree T)
{
	if (T)
	{
		return GetNodeNumber(T->left) + GetNodeNumber(T->right) + 1;
	} 
	else
	{
		return 0;
	}
}

//前序遍歷
void PreShow(Tree T)
{
	if (!T)
	{
		return;
	}
	
	printf("%c ", T->id);
	PreShow(T->left);
	PreShow(T->right);
}

//中序遍歷
void MidShow(Tree T)
{
	if (!T)
	{
		return;
	}
	
	MidShow(T->left);
	printf("%c ", T->id);
	MidShow(T->right);
}

//後序遍歷
void BackShow(Tree T)
{
	if (!T)
	{
		return;
	}
	
	BackShow(T->left);
	BackShow(T->right);
	printf("%c ", T->id);
}

//層序遍歷
void LevelShow(Tree T)
{
	if (!T)
	{
		return;
	}

	Queue m_queue;
	Queue *Q;
	QueueNode *p, *q;

	Q = &m_queue;
	InitQueue(Q); //佇列初始化

	p = (QueueNode *)malloc(sizeof(QueueNode));
	p->next = NULL;
	p->treenode = T;
	InQueue(Q, p); //根節點進隊

	while (!IsQueueEmpty(Q))
	{
		OutQueue(Q, &q); //當前隊首節點出隊
		printf("%c ", q->treenode->id);

		if (q->treenode->left) //左孩子非空,則左孩子進隊
		{
			p = (QueueNode *)malloc(sizeof(QueueNode));
			p->next = NULL;
			p->treenode = q->treenode->left;
			InQueue(Q, p);
		}
		if (q->treenode->right) //右孩子非空,則右孩子進隊
		{
			p = (QueueNode *)malloc(sizeof(QueueNode));
			p->next = NULL;
			p->treenode = q->treenode->right;
			InQueue(Q, p);
		}
	}
}

//初始化佇列
void InitQueue(Queue *q)
{
	q->front = NULL;
	q->rear = NULL;
}

//佇列是否為空
bool IsQueueEmpty(Queue *q)
{
	if (q->front)
	{
		return false;
	} 
	else
	{
		return true;
	}
}

//進隊
void InQueue(Queue *q, QueueNode * p)
{
	if (IsQueueEmpty(q))
	{
		q->front = p;
		q->rear = p;
	} 
	else
	{
		q->rear->next = p;
		q->rear = p;
	}
}

//出隊
void OutQueue(Queue *q, QueueNode **p)
{
	*p = q->front;

	if (q->front == q->rear) //只有1個節點
	{
		q->front = NULL;
		q->rear = NULL;
	} 
	else
	{
		q->front = q->front->next;
	}
}

//清除二叉樹
void ClearTree(Tree *T)
{
	if (!*T)
	{
		return;
	}

	ClearTree(&(*T)->left);
	ClearTree(&(*T)->right);
	free(*T);
	*T = NULL;
}

//二叉樹是否為空
bool IsTreeEmpty(Tree T)
{
	if (T)
	{
		return false;
	} 
	else
	{
		return true;
	}
}