五、求二叉树中第K小元素

题目描述:给定一棵二叉搜索树,请找出其中的第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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值