1. 程式人生 > >二叉搜尋樹建立、插入、刪除、前繼節點、後繼節點之c++實現

二叉搜尋樹建立、插入、刪除、前繼節點、後繼節點之c++實現

#include "stdafx.h"
#include <string>
#include <stdlib.h>
#include <iostream>

using namespace std;

typedef struct Node
{
	int key;                //鍵值
	struct Node *left;		//左節點
	struct Node *right;     //右節點
	struct Node *father;	//父節點
	int times;              //節點出現的次數
} Node, *pNode;

void creatBinarySearchTree(pNode &pBSTTree, int *ptr, int len);
void insertNode(pNode &pBSTTree, int value);
void mallocInitNode(pNode &pInsertNode, int value);
pNode findMinNode(pNode &pTree);
pNode findMaxNode(pNode &pTree);
pNode findPredecessor(pNode &pSearchNode);
pNode findSuccessor(pNode &pSearchNode);
void deleteNode(pNode& pdeleteNode);
void changeFatherChildNode(pNode& pdeleteNode, pNode& pNewChildNode);

int main()
{
	int a[] = {15,15, 6, 18, 3, 7, 17, 20, 2, 4, 13, 9};
	int len = sizeof(a) / sizeof(int);	
	pNode pBSTTree = NULL;
	pNode pPreNode = NULL;
	pNode pSuccessor = NULL;

	/* 建立二叉查詢樹 */
	creatBinarySearchTree(pBSTTree, a, len);

	/* 尋找二叉查詢樹中的最大值 */
	cout << "最小值的節點為:" << findMinNode(pBSTTree)->key << endl;
	cout << "最大值的節點為:" << findMaxNode(pBSTTree)->key << endl;

	/* 尋找某個節點的前驅節點 */
	pPreNode = findPredecessor(pBSTTree->left->right);
	if (NULL != pPreNode)
	{
		cout << "該節點的前驅節點為:" << pPreNode->key << endl;
	}
	else
	{
		cout << "該節點無前驅節點" << endl;
	}

	/* 尋找某個節點的後繼節點 */
	pSuccessor = findSuccessor(pBSTTree->left->left->left);
	if (NULL != pPreNode)
	{
		cout << "該節點的後繼節點為:" << pSuccessor->key << endl;
	}
	else
	{
		cout << "該節點無後繼節點" << endl;
	}

	/* 刪除某個節點 */
	deleteNode(pBSTTree->right->right);
	deleteNode(pBSTTree->left->left);
	cout << "最小值的節點為:" << findMinNode(pBSTTree)->key << endl;
	pSuccessor = findSuccessor(pBSTTree->left->left);
	if (NULL != pPreNode)
	{
		cout << "該節點的後繼節點為:" << pSuccessor->key << endl;
	}
	else
	{
		cout << "該節點無後繼節點" << endl;
	}

	free(pBSTTree);
	pBSTTree = NULL;
	return 0;
}

/* 建立一個二叉查詢樹 */
void creatBinarySearchTree(pNode &pBSTTree, int *ptr, int len)
{
	for (int i = 0; i < len; i++)
	{
		insertNode(pBSTTree, *(ptr + i));
	}
}


/* 插入一個節點,複雜度為O(nlogn) */
void insertNode(pNode &pBSTTree, int value)
{
	pNode pInsertNode;

	/* 第一個節點,直接插入 */
	if (NULL == pBSTTree)
	{
		mallocInitNode(pInsertNode, value);
		pBSTTree = pInsertNode;
		return;
	}

	/* 如果鍵值已經存在的話,只需要times++ */
	if (value == pBSTTree->key)
	{
		pBSTTree->times++;
		return;
	}

	/* 如果小於本節點的值,且該節點無左孩子 */
	if ((NULL == pBSTTree->left) && (value < pBSTTree->key))
	{
		mallocInitNode(pInsertNode, value);
		pInsertNode->father = pBSTTree;
		pBSTTree->left = pInsertNode;		
		return;
	}

	/* 如果大於本節點的值,且該節點無右孩子 */
	if ((NULL == pBSTTree->right) && (value > pBSTTree->key))
	{
		mallocInitNode(pInsertNode, value);
		pInsertNode->father = pBSTTree;
		pBSTTree->right = pInsertNode;
		return;
	}

	/* 如果小於本節點的值,但是該節點已經有左孩子,那麼就繼續遞迴 */
	if ((NULL != pBSTTree->left) && (value < pBSTTree->key))
	{
		insertNode(pBSTTree->left, value);
	}

	/* 如果大於本節點的值,但是該節點已經有右孩子,那麼就繼續遞迴 */
	if ((NULL != pBSTTree->right) && (value > pBSTTree->key))
	{
		insertNode(pBSTTree->right, value);
	}
}

/* 建立新節點並初始化 */
void mallocInitNode(pNode &pInsertNode, int value)
{
	pInsertNode = (pNode)malloc(sizeof(Node));
	pInsertNode->key = value;
	pInsertNode->father = NULL;
	pInsertNode->left = NULL;
	pInsertNode->right = NULL;
	pInsertNode->times = 1;
}

/* 尋找二叉樹中最小的節點和最大的節點 */
pNode findMinNode(pNode &pTree)
{
	pNode pTemp = pTree;
	while (NULL != pTemp->left)
	{
		pTemp = pTemp->left;
	}
	return pTemp;


}

pNode findMaxNode(pNode &pTree)
{
	pNode pTemp = pTree;
	while (NULL != pTemp->right)
	{
		pTemp = pTemp->right;
	}
	return pTemp;
}

/* 找出前驅節點 */
pNode findPredecessor(pNode &pSearchNode)
{
	/* 如果左子樹存在的話,則返回左子樹中最大的節點,即為比它小的之中的最大的節點 */
	if (NULL != pSearchNode->left)
	{
		return findMaxNode(pSearchNode->left);
	}

	/* 如果左子樹不存在的話,則需要往上找,直到找到目標節點是目標節點父親節點的右孩子 */
	pNode pTemp = pSearchNode;
	while(pTemp != pTemp->father->right)
	{
		pTemp = pTemp->father;
	}
	return pTemp->father;
}

/* 找出後繼節點 */
pNode findSuccessor(pNode &pSearchNode)
{
	/* 如果右子樹存在的話,則返回右子樹中最小的節點,即為比它大的之中的最小的節點 */
	if (NULL != pSearchNode->right)
	{
		return findMinNode(pSearchNode->right);
	}

	/* 如果左子樹不存在的話,則需要往上找,直到找到目標節點是目標節點父親節點的右孩子 */
	pNode pTemp = pSearchNode;
	while(pTemp != pTemp->father->left)
	{
		pTemp = pTemp->father;
	}
	return pTemp->father;
}

void deleteNode(pNode& pdeleteNode)
{
	/* 1.判斷該節點的個數,如果節點的個數大於或等於1,則直接將該節點的個數-1 */
	if (1 < pdeleteNode->times)
	{
		pdeleteNode->times--;
		return;
	}
	/* 2.如果該節點只有一個,那麼考慮刪除 */
	/* 2.1 如果該節點沒有孩子,則直接刪除 */
	pNode pTemp = NULL;
	if ((NULL == pdeleteNode->left) && (NULL == pdeleteNode->right))
	{
		changeFatherChildNode(pdeleteNode, pTemp);
	}
	/* 2.2 如果該節點只有一個孩子,那麼直接用該孩子代替該節點 */
	else if ((NULL == pdeleteNode->left) && (NULL != pdeleteNode->right))
	{
		changeFatherChildNode(pdeleteNode, pdeleteNode->right);
	}
	else if ((NULL == pdeleteNode->right) && (NULL != pdeleteNode->left))
	{
		changeFatherChildNode(pdeleteNode, pdeleteNode->left);
	}
	/* 2.3 如果該節點有兩個孩子,那麼考慮用該節點的前驅或者後繼來代替該節點。在此,我們選擇用前驅代替該節點 */
	else
	{
		pTemp = findPredecessor(pdeleteNode);
		pNode pRightChild = pdeleteNode->right;
		changeFatherChildNode(pdeleteNode, pTemp);
		pTemp->right = pRightChild;
	}
}

void changeFatherChildNode(pNode& pdeleteNode, pNode& pNewChildNode)
{
	if (pdeleteNode == pdeleteNode->father->right)
	{
		pdeleteNode->father->right = pNewChildNode;			
	}
	else
	{
		pdeleteNode->father->left = pNewChildNode;
	}
}
程式碼執行結果: