[C++] Simulationsimplementierung rekursiver und nicht rekursiver Methoden des binären Suchbaums (K-, KV-Baum).


Vorwort

Fügen Sie hier eine Bildbeschreibung ein

1. K-Baum

K-Modell: Das K-Modell hat nur den Schlüssel als Schlüsselcode. In der Struktur muss nur der Schlüssel gespeichert werden, und der Schlüsselcode ist der Wert, nach dem gesucht werden muss.

1. Definition des Knotens

template<class K>
struct BSTreeNode
{
    
    
	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;

	BSTreeNode(const K&key)
		:_left(nullptr),_right(nullptr),_key(key)
	{
    
    }
};

2.Konstrukteur

template<class K>
class BSTree {
    
    
	typedef BSTreeNode<K> Node;
public:
	BSTree() {
    
    
		_root = nullptr;
	}

3.Kopieren Sie den Konstruktor

BSTree(const BSTree<K>& t) {
    
    
		_root = Copy(t._root);
	}
Node* Copy(Node* root) {
    
    
		if (root == nullptr) {
    
    
			return nullptr;
		}
		//递归进行拷贝
		Node* copyroot = new Node(root->_key);
		copyroot->_left = Copy(root->_left);
		copyroot->_right = Copy(root->_right);
		return copyroot;
	}

4. Überlastung des Zuweisungsoperators

BSTree<K>& operator=(BSTree<K> t) {
    
    
//先拷贝出t,让_root指向t的位置,进行交换
//后续调用析构函数直接析构t._root
		swap(_root, t._root);
		return *this;
	}

5. Destruktor

~BSTree() {
    
    
		Destroy(_root);
	}
	void Destroy(Node*& root) {
    
    
		if (root == nullptr) {
    
    
			return;
		}
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
		root = nullptr;
	}

6. Im binären Suchbaum suchen (find)

Durchsuchen eines binären Suchbaums
a. Beginnen Sie mit dem Vergleich und der Suche von der Wurzel aus. Wenn sie größer als die Wurzel ist, suchen Sie nach rechts. Wenn sie kleiner als die Wurzel ist, suchen Sie nach links.
b. Die Höhe wird meistens durchsucht. Wenn sie leer ist, wurde sie noch nicht gefunden. Dieser Wert existiert nicht.

1. Nicht rekursiv

bool Find(const K& key) {
    
    
		Node* cur = _root;
		while (cur) {
    
    
			if (cur->_key < key) {
    
    
				//当前值比要查找的值小
				//到右树去查找
				cur = cur->_right;
			}
			else if (cur->_key > key) {
    
    
				cur = cur->_left;
			}
			else {
    
    
				//相等,说明找到了
				return true;
			}
		}
		return false;
	 }

2. Rekursion

bool _FindR(Node*root,const K& key) {
    
    
		if (root == nullptr) {
    
    
			//说明已经找完没找到
			return false;
		}
		if (root->_key < key) {
    
    
			return _FindR(root->_right, key);
		}
		else if (root->_key > key) {
    
    
			return _FindR(root->_left, key);
		}
		else {
    
    
			return true;
		}
	}

7. Einfügen in den binären Suchbaum (Einfügen)

. Einfügen in einen binären Suchbaum.
Der spezifische Vorgang des Einfügens ist wie folgt:
a. Wenn der Baum leer ist, fügen Sie direkt einen Knoten hinzu und weisen Sie ihn dem Wurzelzeiger zu.
b. Wenn der Baum nicht leer ist, suchen Sie die Einfügeposition entsprechend den Eigenschaften des binären Suchbaums und fügen Sie den neuen Knoten ein.

1. Nicht rekursiv

bool Insert(const K& key) {
    
    
		if (_root == nullptr) {
    
    
			_root = new Node(key);
			//树为空先建立结点
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur) {
    
    //寻找要插入位置
			if (cur->_key < key) {
    
    
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key) {
    
    
				parent = cur;
				cur = cur->_left;
			}
			else {
    
    
				//树中已经有key值不能再插入
				return false;
			}
		}
		cur = new Node(key);//cur为要插入结点
		if (parent->_key < key) {
    
    
			//判断cur插在父结点的左数还是右树
			parent->_right = cur;
		}
		else {
    
    
			parent->_left = cur;
		}
		return true;//插入成功
	 }

2. Rekursion

Fügen Sie hier eine Bildbeschreibung ein

bool InsertR(const K&key) {
    
    
		return _InsertR(_root, key);
	}
	bool _InsertR(Node*& root, const K& key) {
    
    
		//这里为结点指针的引用,可以不需要父结点直接修改
		if (root == nullptr) {
    
    
			root = new Node(key);
			return true;
		}
		if (root->_key < key) {
    
    
			return 	_InsertR(root->_right, key);
		}
		else if (root->_key > key) {
    
    
			return _InsertR(root->_left, key);
		}
		else {
    
    return false;}
	}

8.Löschen des binären Suchbaums (Erase)

Überprüfen Sie zunächst, ob sich das Element im binären Suchbaum befindet. Wenn es nicht vorhanden ist, geben Sie es zurück. Andernfalls kann der zu löschende Knoten in die folgenden vier Situationen unterteilt werden: a. Der zu löschende Knoten hat keine untergeordneten
Knoten
. b. Der zu löschende Knoten ist nur der linke untergeordnete Knoten.
c. Der zu löschende Knoten ist nur der rechte untergeordnete Knoten
. d. Der zu löschende Knoten ist der linke und der rechte untergeordnete Knoten.
Es scheint, dass es 4 Situationen dafür gibt Knoten, der gelöscht werden soll. Die tatsächliche Situation a kann mit Situation b oder c zusammengeführt werden. Der eigentliche Löschvorgang
ist also wie folgt:
Fall b: Löschen Sie den Knoten und stellen Sie sicher, dass der übergeordnete Knoten des gelöschten Knotens auf den linken untergeordneten Knoten zeigt des gelöschten Knotens –
Fall c der direkten Löschung: Löschen Sie den Knoten und stellen Sie sicher, dass der übergeordnete Knoten des gelöschten Knotens auf den linken untergeordneten Knoten des gelöschten Knotens zeigt. Der übergeordnete Knoten zeigt auf den rechten untergeordneten Knoten des gelöschten Knotens – Fall d der direkten Löschung
: Suchen Sie den ersten Knoten in der mittleren Reihenfolge (den kleinsten Schlüsselcode) in seinem rechten Teilbaum und füllen Sie ihn mit seinem Wert, bis er gelöscht wird. Knoten, und behandeln Sie dann das Löschproblem der Löschung der Knotenersetzungsmethode

Fügen Sie hier eine Bildbeschreibung ein

Fügen Sie hier eine Bildbeschreibung ein

1. Nicht rekursiv

	bool Erase(const K& key) {
    
    
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur) {
    
    //寻找要删除结点
			if (cur->_key < key) {
    
    
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key) {
    
    
				parent = cur;
				cur = cur->_left;
			}
			
			else {
    
    //找到要删除结点
				//1.   要删除节点左边为空
				if (cur->_left == nullptr) {
    
    
					if (cur == _root) {
    
    
						//要删除结点为根节点,则改变根节点位置
						_root = _root->_right;
					}
					else {
    
    
						//判断要删除结点在父结点的左子树还是右子树
						if (parent->_right == cur) {
    
    
							//在父结点右子树则让其指向删除结点的右子树
							parent->_right = cur->_right;
						}
						else {
    
    
							parent->_left = cur->_right;
						}
					}
				}
				//2.     要删除节点右边为空
				else if (cur->_right == nullptr) {
    
    
					if (cur == _root) {
    
    
						//要删除结点为根节点,则改变根节点位置
						_root = _root->_left;
					}
					else {
    
    
						//判断要删除结点在父结点的左子树还是右子树
						if (parent->_right == cur) {
    
    
							parent->_right = cur->_left;
						}
						else {
    
    
							parent->_left = cur->_left;
						}
					}
				}
				else {
    
    //3.要删除结点左右子树都不为空
					Node* parent = cur;
					Node* leftMax = cur->_left;
					//寻找可替代结点,替代过好要满足二叉搜索树的性质
					//要删除结点左子树的最大值,或者右子树的最小值
					while (leftMax->_right) {
    
    
						//寻找左子树的最大值
						parent = leftMax;
						leftMax = leftMax->_right;
					}
					swap(leftMax->_key, cur->_key);
					//替代结点与被删除结点的值交换
					//这样leftMax就为要被删除的结点
					if (parent->_left == leftMax) {
    
    
						//判断leftMax在父结点的左子树还是右子树
						parent->_left = leftMax->_left;
					}
					else {
    
    
						parent->_right = leftMax->_left;
					}//改变指向
					cur = leftMax;
				}
				delete cur;
				return true;
			}	
		}
		return false;
 }

2. Rekursion

bool EraseR(const K&key) {
    
    
		return _EraseR(_root, key);
	}

bool _EraseR(Node*& root, const K& key) {
    
    
		//这里为结点指针的引用,可以不需要父结点直接修改
		if (root == nullptr) {
    
    
			return false;
		}
		if (root->_key < key) {
    
    
			return _Erase(root->_right, key);
		}
		else if (root->_key > key) {
    
    
			return _Erase(root->_left, key);
		}//寻找要删除结点
		else {
    
    
			Node* del = root;
			//1. 要删除节点左边为空
			if (root->_left == nullptr) {
    
    
				root = root->_right;
			}
			//2. 要删除节点右边为空
			else if (root->_right == nullptr) {
    
    
				root = root->_left;
			}
			else {
    
    
				//3.要删除结点左右都不为空
				Node* leftMax = root->_left;
				while (leftMax->_right) {
    
    
					//寻找替代结点
					leftMax = leftMax->_right;
				}
				swap(root->_key, leftMax->_key);
				//交换值后,要删除的结点为leftMax,其在root的左子树
				return _Erase(root->_left, key);
			}
			delete del;
			return true;
		}
	}

9. In-Order-Durchquerung (InOrder)

void InOrder() {
    
    
		_InOrder(_root);
		cout << endl;
	}
void _InOrder(Node* root) {
    
    
		if (root == nullptr) {
    
    
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

2. KV-Baum

KV-Modell: Jeder Schlüsselschlüssel hat einen entsprechenden Wertwert, dh das Schlüssel-Wert-Paar von <Schlüssel, Wert>

namespace key_value {
    
    
	template<class K, class V>
	struct BSTreeNode
	{
    
    
		BSTreeNode<K, V>* _left;
		BSTreeNode<K, V>* _right;
		K _key;
		V _value;

		BSTreeNode(const K& key, const V& value)
			:_left(nullptr), _right(nullptr), _key(key), _value(value)
		{
    
    }
	};

	template<class K, class V>
	class BSTree {
    
    
		typedef BSTreeNode<K, V> Node;
	public:
		BSTree() {
    
    
			_root = nullptr;
		}

		BSTree(const BSTree<K, V>& t) {
    
    
			_root = Copy(t._root);
		}

		BSTree<K, V>& operator=(BSTree<K, V> t) {
    
    
			swap(_root, t._root);
			return *this;
		}

		~BSTree() {
    
    
			Destroy(_root);
		}



		bool InsertR(const K& key, const V& value) {
    
    
			return _InsertR(_root, key, value);
		}

		bool EraseR(const K& key) {
    
    
			return _Erase(_root, key);
		}

		Node* FindR(const K& key) {
    
    
			return 	_FindR(_root, key);
		}
		void InOrder() {
    
    
			_InOrder(_root);
			cout << endl;
		}



	private:
		Node* Copy(Node* root) {
    
    
			if (root == nullptr) {
    
    
				return nullptr;
			}
			Node* copyroot = new Node(root->_key);
			copyroot->_left = Copy(root->_left);
			copyroot->_right = Copy(root->_right);
			return copyroot;
		}

		void Destroy(Node*& root) {
    
    
			if (root == nullptr) {
    
    
				return;
			}
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
			root = nullptr;
		}

		Node* _FindR(Node* root, const K& key) {
    
    
			if (root == nullptr) {
    
    
				return nullptr;
			}
			if (root->_key < key) {
    
    
				return _FindR(root->_right, key);
			}
			else if (root->_key > key) {
    
    
				return _FindR(root->_left, key);
			}
			else {
    
    
				return root;
			}

		}

		bool _InsertR(Node*& root, const K& key, const V& value) {
    
    
			if (root == nullptr) {
    
    
				root = new Node(key, value);
				return true;
			}
			if (root->_key < key) {
    
    
				return _InsertR(root->_right, key, value);
			}
			else if (root->_key > key) {
    
    
				return _InsertR(root->_left, key, value);
			}
			else {
    
    
				return false;
			}
		}

		bool _Erase(Node*& root, const K& key) {
    
    
			if (root == nullptr) {
    
    
				return false;
			}
			if (root->_key < key) {
    
    
				return _Erase(root->_right, key);
			}
			else if (root->_key > key) {
    
    
				return _Erase(root->_left, key);
			}
			else {
    
    
				Node* del = root;
				if (root->_left == nullptr) {
    
    
					root = root->_right;
				}
				else if (root->_right == nullptr) {
    
    
					root = root->_left;
				}
				else {
    
    
					Node* leftMax = root->_left;
					while (leftMax->_right) {
    
    
						leftMax = leftMax->_right;
					}
					swap(root->_key, leftMax->_key);
					return _Erase(root->_left, key);
				}
				delete del;
				return true;
			}
		}


		void _InOrder(Node* root)
		{
    
    
			if (root == NULL){
    
    return;}
			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);
		}

	private:
		Node* _root;
	};
}

Leistung des binären Suchbaums

Fügen Sie hier eine Bildbeschreibung ein

Die höchste Suchhöhe mal O(N)

Acho que você gosta

Origin blog.csdn.net/m0_74774759/article/details/132210067
Recomendado
Clasificación