题目描述:给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
解题思路:
先遍历二叉树后进行比较,遍历二叉树需要使用中序法
知识:
各种树的概念、查找二叉树的方法、若要求第K大元素
代码:
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if(pRoot==nullptr||k==0)
return nullptr;
return kthNodeCode(pRoot,k);
}
TreeNode* kthNodeCode(TreeNode* pRoot,int & k)
{
TreeNode* target=nullptr;
//中序遍历
if(pRoot->left!=nullptr)
target=kthNodeCode(pRoot->left,k);
if(target==nullptr)
{
if(k==1)
target=pRoot;
k--;
}
if(target==nullptr&&pRoot->right!=nullptr)
target=kthNodeCode(pRoot->right,k);
// return target;
return target;
}
};
补充学习:
二叉查找树BTS(二叉搜索树,二叉排序树):
根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一节点的值。
建立树加插入数据的过程:
struct Node
{
int key;
Node * left;
Node *right;
};
Node *newNode(int item)
{
Node* temp = new Node;
temp->key=item;
temp->left = NULL;
temp->right = NULL;
}
Node* insert(Node* node, int key)
{
if (node == NULL) { return newNode(key); }
if (key < node->key) { node->left = insert(node->left, key); }
else if (key>node->key) { node->right = insert(node->right, key); }
return node;
}
插入过程:
1、若当前二叉树为空,则插入的元素为根节点。
2、若插入的元素值小于根节点值,则递归从根节点的左子树中找到可插入位置。
3、若插入的元素值大于根节点值,则递归从根节点的右子树中找到可插入位置。
Node* insert(Node* node,int key)
{
if(node==NULL) return newNode(key);
if(key<node-<key)
node->left=insert(node->left,key);
else if(key>node->key)
node->right=insert(node->right,key);
}
删除过程:https://blog.youkuaiyun.com/hansionz/article/details/81988752?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-8.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-8.channel_param
1、待删除节点Z为叶子节点,则直接删除该节点。修改父节点的指针。
2、待删除节点Z为单支节点(只有左子树或者右子树),让Z的子树与Z的父节点相连,删除节点Z。
3、待删除节点Z左右子树都不为空。
int RemoveTree(Node** root, int x)
{
if ((*root) == NULL) { return 0; }
//要删除的数小于根节点的数,说明删除的结点在左树
if ((*root)->key > x) { RemoveTree(&(*root)->left, x); }
//要删除的数大于根节点的数,说明删除的结点在右数
else if ((*root)->key < x) { RemoveTree(&(*root)->right, x); }
//*root为一定要删除的结点
else
{
//记录要释放的结点
Node* del = *root;
//1.左子树或者右子树为空
if ((*root)->left = NULL) { *root = (*root)->right, free(del); }
else if((*root)->right = NULL) { *root = (*root)->left, free(del); }
//2.左右子树都不为空,替换删除法
else
{
Node* replace = (*root)->right;
while (replace->left)
{
replace = replace->left;
}
(*root)->key = replace->key;
RemoveTree(&(*root)->right, replace->key);
}
}
}
遍历过程:https://blog.youkuaiyun.com/qq_38846633/article/details/81877582?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
1、前序遍历(递归和非递归两种):先根节点,后左孩子节点,再右孩子结点。
void preorder(Node* root)
{
if (root == NULL) { cout << "二叉树为空" << endl; return; }
else
{
cout << root->key;
preorder(root->left);
preorder(root->right);
}
}
//非递归
void preorder2(Node* root)
{
Node *p = root;
stack<Node*>s;
s.push(root);
while (!s.empty)
{
p = s.top();
s.pop();
if (p != NULL)
{
cout << p->key;
s.push(p->right);
s.push(p->left);
}
}
}
2、中序遍历(递归和非递归两种):先左孩子结点,后根节点,再右孩子结点。
3、后序遍历(递归和非递归两种):先做孩子节点,后右孩子结点,再根节点。
获取最大元素的节点:
1、如果根节点无右子树,则返回根节点。
2、依次查询根节点的右子树节点,返回右子树的最后一个右节点。
void maximum(Node* root)
{
if (root->right = NULL)
cout << root->key;
else
maximum(root->right);
}
获取最小元素的节点:
1、如果根节点无左子树,则返回根节点。
2、依次查询跟节点的左子树节点,返回左子树的最后一个左节点。
void minimum(Node* root)
{
if (root->left = NULL)
cout << root->key;
else
minimum(root->left);
}
求给定树中第K个最大元素的函数:
void kthLargestUtil(Node* root, int k)
{ //避免无效搜索
int c = 0;
if (root == NULL || c >= k)
return;
//每查找右子树则标记自加
kthLargestUtil(root->right, k);
c++;
if (c == k)
{
cout << root->right << endl;
return;
}
kthLargestUtil(root->left, k);
}
求给定树中第K个最小元素的函数:
void kthMinistUtil(Node* root, int k)
{
int c = 0;
if (root == NULL || k < c)
return;
kthMinistUtil(root->left, k);
c++;
if (c == k)
{
cout << root->left;
return;
}
kthMinistUtil(root->right, k);
}
总代码:
#include<iostream>
using namespace std;
#include<stack>
/*
二叉查找树:根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一节点的值,
*/
struct Node
{
int key;
Node* left, *right;
};
Node *newNode(int item)
{
Node* temp = new Node;
temp->key = item;
temp->left = NULL;
temp->right = NULL;
return temp;
}
//前序遍历
void Preorder(Node* root)
{
if (root == NULL) { cout << "二叉树为空" << endl; return; }
else
{
cout << root->key;
Preorder(root->left);
Preorder(root->right);
}
}
void Preorder2(Node* root)
{
Node *p = root;
stack<Node*>s;//定义一个Node* 的栈,将P初始化指向root结点,先压右后压左
s.push(root);
while(!s.empty())
{
p = s.top();
s.pop();
if (p != NULL)
{
cout << p->key;
s.push(p->right);
s.push(p->left);
}
}
}
//中序遍历
void Mindorder(Node* root)
{
if (root == NULL) { cout << "二叉树为空" << endl; return;}
else
{
Mindorder(root->left);
cout << root->key;
Mindorder(root->right);
}
}
void Mindorder2(Node* root)
{
Node *p = root;
stack<Node*>s;
while (!s.empty()||p!=NULL)
{
while (p != NULL)
{
s.push(p);
p = p->left;
}
if(!s.empty())
{
p = s.top();
cout << p->key;
s.pop();
p = p->right;
}
}
}
//后序遍历
void Lastorder(Node* root)
{
if (root == NULL) { cout << "二叉树为空" << endl; return; }
else
{
Lastorder(root->left);
Lastorder(root->right);
cout << root->key;
}
}
void Lastorder(Node* root)
{
Node*p = root;
Node*q = NULL;
stack<Node*>s;
while (!s.empty() || p != NULL)
{
while (p != NULL)
{
s.push(p);
p = p->left;
}
p = s.top();
cout << p->key;
s.pop();
if (!s.empty)
{
q = s.top();
}
if (p == q->left)
{
p == q->right;
}
else
{
p = NULL;
}
}
}
//获取元素最大结点
Node maximum(Node* root)
{ if (root->right == NULL)
cout << root->key;
else
maximum(root->right);
}
//获取元素最小结点
Node minimum(Node* root)
{
if (root->left == NULL)
cout << root->key;
else
minimum(root->left);
}
//求给定树中第k个最大元素的函数
void kthLargestUtil(Node* root, int k, int &c)
{
//避免无效搜索
if (root == NULL || c >= k)
return;
//执行反向顺序遍历,以便首先访问最大的元素
kthLargestUtil(root->right, k, c);
//增加访问节点的计数
c++;
//如果c现在变成k,那么这个是第k个
if (c == k)
{
cout << "第"<<k<<"个largest element is:"
<< root->key << endl;
return;
}
//重复为左子树
kthLargestUtil(root->left, k, c);
}
void kthLargest(Node *root, int k)
{
//求第k个元素的函数
int c = 0;
kthLargestUtil(root, k, c);
}
//求给定树中第K个最小元素的函数
void kthMinistUtil(Node* root, int k, int &c)
{//避免无效搜索
if (root == NULL || c >= k)
return;
//执行反向顺序遍历,以便首先访问最大的元素
kthLargestUtil(root->left, k, c);
//增加访问节点的计数
c++;
//如果c现在变成k,那么这个是第k个
if (c == k)
{
cout << "第" << k << "个ministest element is:"
<< root->key << endl;
return;
}
//重复为左子树
kthLargestUtil(root->right, k, c);
}
void kthMinist(Node *root, int k)
{
//求第k个元素的函数
int c = 0;
kthMinistUtil(root, k, c);
}
//插入数据
Node* insert(Node* node, int key)
{
//如果树为空,返回 newNod
if (node == NULL) return newNode(key);
//否则,重复树
if (key < node->key)
node->left = insert(node->left, key);
else if (key>node->key)
node->right = insert(node->right, key);
return node;
}
//删除结点
int RemoveTree(Node** root, int x)
{
if ((*root) == NULL) { return 0; }
//要删除的数小于根节点的数,说明删除的结点在左树
if ((*root)->key > x) { RemoveTree(&(*root)->left, x); }
//要删除的数大于根节点的数,说明删除的结点在右数
else if ((*root)->key < x) { RemoveTree(&(*root)->right, x); }
//*root为一定要删除的结点
else
{
//记录要释放的结点
Node* del = *root;
//1.左子树或者右子树为空
if ((*root)->left = NULL) { *root = (*root)->right, free(del); }
else if((*root)->right = NULL) { *root = (*root)->left, free(del); }
//2.左右子树都不为空,替换删除法
else
{
Node* replace = (*root)->right;
while (replace->left)
{
replace = replace->left;
}
(*root)->key = replace->key;
RemoveTree(&(*root)->left, replace->key);
}
}
}
int main()
{ /* Let us create following BST
50
/ \
30 70
/ \ / \
20 40 60 80 */
Node* root = NULL;
root = insert(root, 50);
insert(root, 30);
insert(root, 20);
insert(root, 40);
insert(root, 70);
insert(root, 60);
insert(root, 80);
int c = 0;
for (int k = 1; k <= 7; k++)
kthLargest(root, k);
return 0;
}