二叉搜索树及应用

 二叉搜索树的特点:

     1.若它的左子树不为空,则左子树上所有结点的值都小于根结点的值。

     2. 若它的右子树不为空,则右子树上所有结点的值都大于根结点的值。

     3.它的左右 也分别为二叉搜索树。

 删除的情况分为四大类,八种情况:

               备注:红色圈表示要删除的结点,蓝色和绿色表示替补结点

.

 

 情况4,5,6刚好与情况1,2,3相反;

 

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>

typedef struct BSTreeNode{
	int key;  // key不允许重复,不允许更改
	struct BSTreeNode *pLeft;
	struct BSTreeNode *pRight;
}BSTreeNode;

//查找(非递归)  找到,返回1;没找到,返回0
int Find(BSTreeNode *pRoot, int key)
{
	BSTreeNode *pNode = pRoot;
	while (pNode != NULL){
		if (key = pNode->key){
			return 1;//根结点是要找的结点
		}
		else if (key < pRoot->key){
			pNode = pNode->pLeft;
		}
		else if (key>pRoot->key){
			pNode = pNode->pRight;
		}
	}
	return 0;//没找到
}

//查找(递归) 找到,返回1;没找到,返回0
int FindR(BSTreeNode *pRoot, int key)
{
	if (pRoot == NULL){
		return 0;
	}
	if (key = pRoot->key){
		return 1;
	}
	if (key < pRoot->key){
		return FindR(pRoot->pLeft, key);
	}
	return FindR(pRoot->pRight, key);
}
//创建一个新结点
BSTreeNode *CreateNode(int key)
{
	BSTreeNode *pNode = (BSTreeNode *)malloc(sizeof(BSTreeNode));
	assert(pNode);

	pNode->key = key;
	pNode->pLeft = pNode->pRight = NULL;
	return pNode;
}
//插入(非递归)0 :成功  -1 失败
int Insert(BSTreeNode **pRoot, int key)
{
	BSTreeNode *pNode = *pRoot;
	BSTreeNode *pParent = NULL;
	while (pNode != NULL){
		if (key == pNode->key){
			return -1;
		}
		else if (key < pNode->key){
			pParent = pNode;
			pNode = pNode->pLeft;
		}
		else{
			pParent = pNode;
			pNode = pNode->pRight;
		}
	}
	if (pParent == NULL){
		*pRoot = CreateNode(key);
        return 0;
	}
	//左还是右
	if (key < pParent->key){
		pParent->pLeft = CreateNode(key);
	}
	else{
		pParent->pLeft = CreateNode(key);
	}
	return 0;
}
//插入(递归)
int InsertR(BSTreeNode **pRoot, int key)
{
	if (*pRoot == NULL){
		*pRoot = CreateNode(key);
		return 0;
	}
	if (key == ((*pRoot)->key)){
		return -1;//要插入的关键字在书中已经存在,所以插入失败
	}
	if (key < ((*pRoot)->key)){
		return InsertR(&(*pRoot)->pLeft, key);
	}
	return InsertR(&(*pRoot)->pRight, key);
}

//删除(非递归)
int Remove(BSTreeNode **pRoot, int key)
{
	BSTreeNode *pNode = *pRoot;
	BSTreeNode *pParent = NULL;
	BSTreeNode *pSwap = NULL;
	BSTreeNode *pSwapParent = NULL;

	while (pNode != NULL) {
		if (key == pNode->key) {
			// 开始删除
			if (pNode->pLeft == NULL) {
				if (pNode == *pRoot) {
					*pRoot = pNode->pRight;
					free(pNode);
					return 0;
				}
				else {
					if (pNode == pParent->pLeft) {
						pParent->pLeft = pNode->pRight;
					}
					else {
						pParent->pRight = pNode->pRight;
					}
					free(pNode);
					return 0;
				}
			}
			else if (pNode->pRight == NULL) {
				if (pNode == *pRoot) {
					*pRoot = pNode->pLeft;
					free(pNode);
					return 0;
				}
				else {
					if (pNode == pParent->pLeft) {
						pParent->pLeft = pNode->pLeft;
					}
					else {
						pParent->pRight = pNode->pLeft;
					}
					free(pNode);
					return 0;
				}
			}
			else {
				// 左右孩子都不为空
				// 这里才用替换法删除
				// 这里采用的是找右子树中最小的
				pSwap = pNode->pRight;
				while (pSwap->pLeft != NULL) {
					pSwapParent = pSwap;
					pSwap = pSwap->pLeft;
				}

				pNode->key = pSwap->key;
				// 删除 pSwap 结点
				if (pSwap == pNode->pRight) {
					pNode->pRight = pSwap->pRight;
				}
				else {
					pSwapParent->pLeft = pSwap->pRight;
				}

				free(pSwap);
				return 0;
			}
		}
		else if (key < pNode->key) {
			pParent = pNode;
			pNode = pNode->pLeft;
		}
		else {
			pParent = pNode;
			pNode = pNode->pRight;
		}
	}
	return -1;
}


//删除(递归)
int RemoveR(BSTreeNode **pRoot, int key)
{
	if (*pRoot == NULL){
		return -1;//失败
	}
	if (key < ((*pRoot)->key)){
		return RemoveR(&(*pRoot)->pLeft, key);
	}
	else if (key>((*pRoot)->key)){
		return RemoveR(&(*pRoot)->pRight, key);
	}

	//处理删除
	if ((*pRoot)->pLeft == NULL){
		*pRoot = (*pRoot)->pRight;
		return 0;//成功删除
	}
	if ((*pRoot)->pRight == NULL){
		*pRoot = (*pRoot)->pLeft;
		return 0;
	}

	//左右子树都不为空,替换删除,左子树中找最大的
	BSTreeNode *pSwap = (*pRoot)->pLeft;
	while (pSwap->pRight){
		pSwap = pSwap->pRight;
	}
	(*pRoot)->key = pSwap->key;
	RemoveR(&((*pRoot)->pLeft), pSwap->key);
	return 0;
}

 利用二叉搜索树判断一个单词拼写是否正确:

思路:先把正确的单词依次插入到一棵二叉搜索树中,在进行查找进而判断该单词的拼写是否正确。找到说明正确。

代码如下:

IsSpellRight.h:

#define _CRT_SECURE_NO_WARNINGS
#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

typedef struct WordTreeNode {
	char	word[20];
	struct WordTreeNode *pLeft;
	struct WordTreeNode *pRight;
}	WordTreeNode;

int Insert(WordTreeNode **ppRoot, const char *word)
{
	if (*ppRoot == NULL) {
		*ppRoot = (WordTreeNode *)malloc(sizeof(WordTreeNode));
		assert(*ppRoot);
		strncpy((*ppRoot)->word, word, 20);
		(*ppRoot)->pLeft = (*ppRoot)->pRight = NULL;
		return 0;
	}

	int r = strncmp((*ppRoot)->word, word, 20);
	if (r == 0) {
		return -1;
	}

	if (r < 0) {
		return Insert(&(*ppRoot)->pLeft, word);
	}

	return Insert(&(*ppRoot)->pRight, word);
}

// 1 表示 正确
// 0 表示 错误
int IsSpellRight(WordTreeNode *pRoot, const char *word)
{
	if (pRoot == NULL) {
		return 0;
	}

	int r = strncmp(pRoot->word, word, 20);
	if (r == 0) {
		return 1;
	}

	if (r < 0) {
		return IsSpellRight(pRoot->pLeft, word);
	}

	return IsSpellRight(pRoot->pRight, word);
}

void App1()
{
	WordTreeNode *pRoot = NULL;
	Insert(&pRoot, "Apple");
	Insert(&pRoot, "Banana");

	char word[20];
	while (1) {
		scanf("%s", word);
		if (IsSpellRight(pRoot, word)) {
			printf("拼写正确\n");
		}
		else {
			printf("拼写错误\n");
		}
	}
}

main.c:

#include"IsSpellRight.h"

int main()
{
	App1();

	return 0;
}

结果显示:

猜你喜欢

转载自blog.csdn.net/ZY_20181010/article/details/81122950