二叉搜索树的特点:
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;
}
结果显示: