本次的課程設計要求建立一顆二叉樹,並且用中序非遞歸方法遍歷該二叉樹,然後判斷該二叉樹是否爲二叉排序樹,如果是二叉排序樹的話進一步要求對結點進行插入和刪除操作,並輸出操作後的結果。
樹結點
typedef struct node
{
struct node *lchild;
struct node *rchild;
int data;
}BiTreeNode, *BiTree;
首先我們要建立一顆二叉樹,這裏我們採用二叉樹的前序遍歷序列和中序遍歷序列遞歸地建立一顆二叉樹,代碼如下:
//二叉排序樹測試用例
int pre[] = { 5, 3, 2, 4, 8, 6 };//前序遍歷
int ino[] = { 2, 3, 4, 5, 6, 8 };//中序遍歷
void BuildBTree(BiTreeNode **T, int preL, int preR, int inoL, int inoR)//遞歸建樹
{
if (preL>preR) return;
int e = pre[preL];
int root = inoL;
while (ino[root] != e&&root <= inoR) ++root;
(*T) = (BiTreeNode *)malloc(sizeof(BiTreeNode));
(*T)->lchild = NULL;
(*T)->rchild = NULL;
(*T)->data = e;
BuildBTree(&(*T)->lchild, preL + 1, preL + root - inoL, inoL, root - 1);
BuildBTree(&(*T)->rchild, preL + root - inoL + 1, preR, root + 1, inoR);
}
然後定義中序非遞歸遍歷函數,這裏用輔助棧實現中序非遞歸遍歷二叉樹算法,代碼如下:
void midvisit(BiTreeNode*root)
{
//中序非遞歸遍歷
printf("中序遍歷結果:");
if (root)
{
BiTreeNode*Stack[100]; int top = -1;
BiTreeNode*p;
p = root;
while (top != -1 || p)
{
while (p)
{
Stack[++top] = p;
p = p->lchild;
}
if (top != -1)
{
p = Stack[top--];
printf("%d", p->data);
p = p->rchild;
}
}
}
putchar('\n');
}
爲了便於對輸出進行比較,順便寫了一個前序遞歸遍歷函數,代碼如下:
void previsit(BiTreeNode* t)
{
if (t)
{
printf("%d", t->data);
previsit(t->lchild);
previsit(t->rchild);
}
}
接下來我們要判斷這顆二叉樹是不是排序二叉樹,算法的思想爲:先對二叉樹進行一次中序遍歷,並且將遍歷結果存儲到數組中,複製該數組然後用快速排序對其進行升序排序,再比較排序前和排序後的數組是否一致,如果有一處不一致則該二叉樹不是排序二叉樹,如果全部一致則爲二叉排序樹,代碼如下:
int cmp(const void*a, const void*b)
{
return *(int*)a - *(int*)b;
}
bool IsSortTree(BiTreeNode* root)
{//判斷是否是二叉排序樹
int size = 0;
int data[MAXSIZE], sortdata[MAXSIZE];
if (root)
{
BiTreeNode*Stack[100]; int top = -1;
BiTreeNode*p;
p = root;
while (top != -1 || p)
{
while (p)
{
Stack[++top] = p;
p = p->lchild;
}
if (top != -1)
{
p = Stack[top--];
//printf("%d", p->data);
data[size++] = p->data;
p = p->rchild;
}
}
}
for (int i = 0; i < size; ++i)
sortdata[i] = data[i];
qsort(sortdata, size, sizeof(int), cmp);
for (int i = 0; i < size; ++i)
{
if (sortdata[i] != data[i])
return false;
}
return true;
}
接來下的兩個函數實現對排序二叉樹新增結點和刪除結點操作。
BiTreeNode* Insert(BiTreeNode*root, int x)
{
if (!root){
root = (BiTreeNode*)malloc(sizeof(BiTreeNode));
root->data = x;
root->lchild = root->rchild = NULL;
}
else{
if (x < root->data)
root->lchild = Insert(root->lchild, x);
else if (x > root->data)
root->rchild = Insert(root->rchild, x);
}
return root;
}
void Del(BiTree&root, int x)
{
if (root == NULL){
return;
}
if (root->data>x){
Del(root->lchild, x);
}
else if (root->data<x){
Del(root->rchild, x);
}
else{ //查找到了刪除節點
if (root->lchild == NULL){ //左子樹爲空
BiTree tempNode = root;
root = root->rchild;
free(tempNode);
}
else if (root->rchild == NULL){ //右子樹爲空
BiTree tempNode = root;
root = root->lchild;
free(tempNode);
}
else{ //左右子樹都不爲空
//一般的刪除策略是左子樹的最大數據 或 右子樹的最小數據 代替該節點(這裏採用查找左子樹最大數據來代替)
BiTree tempNode = root->lchild;
if (tempNode->rchild != NULL){
tempNode = tempNode->rchild;
}
root->data = tempNode->data;
Del(root->lchild, tempNode->data);
}
}
}
這裏我們定義了一個非必須的solve()函數,來實現判斷二叉樹是否爲排序二叉樹以及後續操作。
void solve(BiTreeNode*root)
{
//如果是二叉排序樹,進行結點的插入或刪除。
if (IsSortTree(root))
{
midvisit(root);
Insert(root, 11); //如果是排序樹,插入值11
midvisit(root);
Del(root, 5);//刪除值爲5的結點
midvisit(root);
}
else
return;//不是二叉排序樹 什麼也不做
}
最後就是main()函數了。。。
int main()
{
//freopen("data.txt", "r", stdin);
BiTreeNode*root;
BuildBTree(&root, 0, sizeof(pre) / sizeof(pre[0])-1, 0, sizeof(ino) / sizeof(ino[0])-1);
printf("前序遍歷結果:");
previsit(root);
putchar('\n');
midvisit(root);
if (IsSortTree(root))
printf("YES\n");
else
printf("NO\n");
solve(root);
}
完整代碼代碼如下:
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE (100)
typedef struct node
{
struct node *lchild;
struct node *rchild;
int data;
}BiTreeNode, *BiTree;
//非二叉排序樹測試用例
//int pre[] = { 1, 2, 4, 5, 3, 6, 7 };//前序序列
//int ino[] = { 4, 2, 5, 1, 6, 3, 7 };//中序序列
//二叉排序樹測試用例
int pre[] = { 5, 3, 2, 4, 8, 6 };
int ino[] = { 2, 3, 4, 5, 6, 8 };
void BuildBTree(BiTreeNode **T, int preL, int preR, int inoL, int inoR)//遞歸建樹
{
if (preL>preR) return;
int e = pre[preL];
int root = inoL;
while (ino[root] != e&&root <= inoR) ++root;
(*T) = (BiTreeNode *)malloc(sizeof(BiTreeNode));
(*T)->lchild = NULL;
(*T)->rchild = NULL;
(*T)->data = e;
BuildBTree(&(*T)->lchild, preL + 1, preL + root - inoL, inoL, root - 1);
BuildBTree(&(*T)->rchild, preL + root - inoL + 1, preR, root + 1, inoR);
}
void midvisit(BiTreeNode*root)
{
//中序非遞歸遍歷
printf("中序遍歷結果:");
if (root)
{
BiTreeNode*Stack[100]; int top = -1;
BiTreeNode*p;
p = root;
while (top != -1 || p)
{
while (p)
{
Stack[++top] = p;
p = p->lchild;
}
if (top != -1)
{
p = Stack[top--];
printf("%d", p->data);
p = p->rchild;
}
}
}
putchar('\n');
}
void previsit(BiTreeNode* t)
{
if (t)
{
printf("%d", t->data);
previsit(t->lchild);
previsit(t->rchild);
}
}
int cmp(const void*a, const void*b)
{
return *(int*)a - *(int*)b;
}
bool IsSortTree(BiTreeNode* root)
{//判斷是否是二叉排序樹
int size = 0;
int data[MAXSIZE], sortdata[MAXSIZE];
if (root)
{
BiTreeNode*Stack[100]; int top = -1;
BiTreeNode*p;
p = root;
while (top != -1 || p)
{
while (p)
{
Stack[++top] = p;
p = p->lchild;
}
if (top != -1)
{
p = Stack[top--];
//printf("%d", p->data);
data[size++] = p->data;
p = p->rchild;
}
}
}
for (int i = 0; i < size; ++i)
sortdata[i] = data[i];
qsort(sortdata, size, sizeof(int), cmp);
for (int i = 0; i < size; ++i)
{
if (sortdata[i] != data[i])
return false;
}
return true;
}
BiTreeNode* Insert(BiTreeNode*root, int x)
{
if (!root){
root = (BiTreeNode*)malloc(sizeof(BiTreeNode));
root->data = x;
root->lchild = root->rchild = NULL;
}
else{
if (x < root->data)
root->lchild = Insert(root->lchild, x);
else if (x > root->data)
root->rchild = Insert(root->rchild, x);
}
return root;
}
void Del(BiTree&root, int x)
{
if (root == NULL){
return;
}
if (root->data>x){
Del(root->lchild, x);
}
else if (root->data<x){
Del(root->rchild, x);
}
else{ //查找到了刪除節點
if (root->lchild == NULL){ //左子樹爲空
BiTree tempNode = root;
root = root->rchild;
free(tempNode);
}
else if (root->rchild == NULL){ //右子樹爲空
BiTree tempNode = root;
root = root->lchild;
free(tempNode);
}
else{ //左右子樹都不爲空
//一般的刪除策略是左子樹的最大數據 或 右子樹的最小數據 代替該節點(這裏採用查找左子樹最大數據來代替)
BiTree tempNode = root->lchild;
if (tempNode->rchild != NULL){
tempNode = tempNode->rchild;
}
root->data = tempNode->data;
Del(root->lchild, tempNode->data);
}
}
}
void solve(BiTreeNode*root)
{
//如果是二叉排序樹,進行結點的插入或刪除。
if (IsSortTree(root))
{
midvisit(root);
Insert(root, 11); //如果是排序樹,插入值11
midvisit(root);
Del(root, 5);//刪除值爲5的結點
midvisit(root);
}
else
return;//不是二叉排序樹 什麼也不做
}
int main()
{
//freopen("data.txt", "r", stdin);
BiTreeNode*root;
BuildBTree(&root, 0, sizeof(pre) / sizeof(pre[0])-1, 0, sizeof(ino) / sizeof(ino[0])-1);
printf("前序遍歷結果:");
previsit(root);
putchar('\n');
midvisit(root);
if (IsSortTree(root))
printf("YES\n");
else
printf("NO\n");
solve(root);
}