模拟实现
#include
namespace Schuyler
{
// 因为 vector 容器可以存放任意类型,所以要用模板
template <class T>
class vector
{
public:
// 用迭代器包装任意类型的指针
typedef T* iterator;
typedef const T* const_iterator;
// begin 返回空间起始地址
iterator begin()
{
return _start;
}
// end 返回最后一个有效数据的下个空间的地址
iterator end()
{
return _finish;
}
// const 对象调用,只有读权限,不能写
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
// 扩容
void reserve(int n)
{
if (capacity() < n)
{
int sz = size();
// 开辟新空间
T* p = new T[n];
if (_start)
{
// 旧空间数据拷贝到新空间
for (int i = 0; i < sz;i++)
{
p[i] = _start[i];
}
}
// 释放旧空间
delete[] _start;
// 指针指向新空间
_start = p;
_finish = p + sz;
_endOfStorage = _start + n;
}
}
// 调整 size
void resize(int n, T val = T())
{
// 要求调整的 size 小于 有效数据个数,则直接移动 _finish
if (n < size())
{
_finish = _start + n;
}
else
{
// 要求的 size 大于 容量,则另外开辟一块空间
if (n > capacity())
{
reserve(n);
}
// 从数据末尾存放新的数据 val
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
}
// 数据尾插就是往 _finish 处添数据
void push_back(const T& val)
{
if (capacity() == size())
{
const int newCapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newCapacity);
}
*_finish = val;
++_finish;
}
// 尾删
void pop_back()
{
if (empty())
throw new _exception{ 1, "容器为空" };
--_finish;
}
// 任意位置插入
void insert(iterator pos, const T& val)
{
// 判断是否需要扩容
if (_finish == _endOfStorage)
{
// 计算 pos 离起始位置的距离,方便扩容后找到新空间的 pos
int len = pos - _start;
int newCapacity = capacity() == 0 ? 4 : capacity * 2;
reserve(newCapacity);
}
pos = _start + len;
// 向后挪动数据,插入新输入
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = val;
++_finish;
}
// 删除任意位置元素
iterator erase(iterator pos)
{
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
++it;
}
--_finish;
return pos;
}
// 构造函数给三个成员变量赋初值
vector()
{
_start = nullptr;
_finish = nullptr;
_endOfStorage = nullptr;
}
// 使用迭代器构造 vector
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
// 拷贝构造
vector(const vector<T>& v)
{
_start = new T[v.capacity()];
for (int i = 0; i < v.size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_endOfStorage = _start + v.capacity();
}
private:
void swap(vector<T>& v)
{
_start = v._start;
_finish = v._finish;
_endOfStorage = v._endOfStorage;
}
public:
// 赋值运算符
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
// 析构函数
~vector()
{
if (_start)
{
delete[] _start;
}
_start = _finish = _endOfStorage = nullptr;
}
// vector 索引
T& operator[](int i)
{
if (i >= size())
throw new _exception{ 0, "索引错误" };
return _start[i];
}
const T& operator[](int i)const
{
if (i >= size())
throw new _exception{ 0, "索引错误" };
return _start[i];
}
private:
// 指向数组空间起始位置
iterator _start;
// 指向数组空间中有效数据末尾的下一个位置
iterator _finish;
// 指向数组空间的末尾
iterator _endOfStorage;
public:
// 有效数据个数
int size() const
{
return _finish - _start;
}
// 容器空间大小
int capacity() const
{
return _endOfStorage - _start;
}
// 判断容器是否为空
bool empty()
{
return _finish == _start;
}
};
}
vector 迭代器失效问题:
引起迭代器失效的情况有两种,
另一种
模拟实现
# include
namespace Schuyler
{
class string
{
public:
// 四个默认成员函数
// 构造函数
string(const char* str = "")
{
if (nullptr == str)
throw new _exception{0,"字符串指针为 nullptr"};
int size = strlen(str);
// +1 是为了保留 ‘\0’
_str = new char[size + 1];
strcpy(_str, str);
_size = size;
_capacity = size;
}
// 析构函数
~string()
{
if (_str != nullptr)
{
delete[] _str;
_str = nullptr;
_size = _capacity = 0;
}
}
// 拷贝构造
string(const string& str)
{
_str = nullptr;
_size = _capacity = 0;
// 开辟一块和 str 一样的空间
string tmp(str._str);
// 将新空间和 _str 交换,新空间的字符指针变为 nullptr,tmp 出作用域空间释放
swap(tmp);
}
// 赋值运算符号
string& operator=(string str)
{
// 因为 str 传值类型,会拷贝构造一个临时对象,可以借临时对象来赋值,出作用域,临时对象销毁
swap(str);
return *this;
}
// 对字符串进行索引,const 对象索引返回值不能修改
const char& operator[](int i) const
{
if (i < 0)
throw new _exception{ 1, "字符串索引错误" };
return _str[i];
}
char& operator[](int i)
{
if (i < 0)
throw new _exception{ 1, "字符串索引错误" };
return _str[i];
}
// 扩容
void reserve(int n)
{
if (n > _capacity)
{
// 创建一块新空间,将原本空间中的内容拷贝下来
char* newStr = new char[n + 1];
strncpy(newStr, _str, _size + 1);
// 释放原本空间,更新 _capacity
delete[] _str;
_str = newStr;
_capacity = n;
}
}
void resize(int n, char val = '\0')
{
// 修改的空间小于 size,将 _size 更新,并在末尾添 '\0'
if (n < _size)
{
_size = n;
_str[n] = '\0';
}
else
{
// n > _capacity 需要扩容,当 _size < n < _capacity 时,不需要扩容,只需从 _size 处开始添 '\0',更新 _size
if (n > _capacity)
{
reserve(n);
}
for (int i = _size; i < n; i++)
{
_str[i] = val;
}
_str[n] = '\0';
_size = n;
}
}
// 增删查
// 增
string& insert(int pos, char val)
{
if (pos > _size)
throw new _exception{ 2, "插入位置错误" };
// 判断是否需要增容
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
char* end = _str + _size;
// 从有效字符空间的末尾开始挪动,将 pos 及其之后的数据往后移动
while (end >= _str + pos)
{
*(end + 1) = *end;
end--;
}
// 在 pos 位置插入数据
_str[pos] = val;
_size++;
return *this;
}
void push_back(char ch)
{
insert(_size, ch);
}
string& insert(int pos, const char* str)
{
if (pos > _size)
throw new _exception{ 2, "插入位置错误" };
int len = strlen(str);
if (_size +len > _capacity)
reserve(_size + len);
// 移动 pos 及其之后的数据
char* end = _str + _size;
while (end >= _str + pos)
{
*(end + len) = *end;
end--;
}
strncpy(_str + pos, str, len);
_size += len;
return *this;
}
void append(const char* str)
{
insert(_size, str);
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
// 删除 pos 及其之后的 len 个数据,若不指定 len,则删除 pos 及其之后的全部数据
string& erase(int pos, int len = npos)
{
if (pos >= _size)
throw new _exception{ 3, "删除的位置错误" };
// 计算从 pos 位置开始到字符串结尾的长度
int leftLen = _size - pos;
// 如果 leftLen <= len,则全部删除,否则删除 len 个字符
if (leftLen <= len)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
void clear()
{
_size = 0;
_str[0] = '\0';
}
// 查
int find(char ch, int pos = 0)
{
if (pos >= _size)
throw new _exception{ 4, "查询位置出错" };
for (int i = pos; i < _size; i++)
{
if (_str[i] == ch)
{
return i;
}
}
return npos;
}
int find(const char* str, int pos = 0)
{
if (pos >= _size)
throw new _exception{ 4, "查询位置出错" };
char* ret = strstr(_str, str);
if (ret)
{
return ret - _str;
}
else
{
return npos;
}
}
char* c_str() const
{
return _str;
}
// 迭代器
typedef char* iterator;
typedef const char* const_iterator;
// 返回字符串起始位置
iterator begin()
{
return _str;
}
// 返回字符串最后一个有效字符的下一位置
iterator end()
{
return _str + _size;
}
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
private:
void swap(string& str)
{
std::swap(_str, str._str);
std::swap(_size, str._size);
std::swap(_capacity, str._capacity);
}
private:
// 管理字符空间的指针
char* _str;
// 字符空间有效字符大小
int _size;
// 字符空间大小这里定义成总大小减去'\0'的大小
int _capacity;
// 初始化 -1,表示"字符串末尾",因为 size_t 类型,所以 npos 为无限大
static size_t npos;
};
size_t string::npos = -1;
inline bool operator<(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) < 0;
}
inline bool operator>(const string& s1, const string& s2)
{
return !(s1 < s2);
}
inline bool operator==(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) == 0;
}
inline bool operator<=(const string& s1, const string& s2)
{
return s1 == s2 || s1 < s2;
}
inline bool operator>=(const string& s1, const string& s2)
{
return s1 == s2 || s1 > s2;
}
inline bool operator!=(const string& s1, const string& s2)
{
return !(s1 == s2);
}
std::ostream& operator<<(std::ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
std::istream& operator>>(std::istream& in, string& s)
{
s.clear();
char ch;
ch = in.get();
while (ch != ' ' || ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
std::istream& getline(std::istream& in, string& s)
{
s.clear();
char ch;
ch = in.get();
while (ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
}
若想写一个简洁版的 string,只需包含四个默认成员函数即可,可以是传统写法,也可以是现代写法。
模拟实现
namespace Schuyler
{
// list 节点类型
template
struct ListNode
{
ListNode(const T& val = T())
{
_val = val;
_pre = nullptr;
_next = nullptr;
}
T _val;
ListNode* _pre;
ListNode* _next;
};
// list 的迭代器是对原生指针的封装
// 这里的模板使用 3 种类型,是为了可以同时用一份代码,实例化出 const 和 非 const 的迭代器
template
class ListIterator
{
typedef ListIterator self;
typedef ListNode* node;
public:
// 通过一个节点指针去初始化迭代器指针
ListIterator(node* pNode)
{
_node = pNode;
}
// 通过迭代器去初始化一个迭代器指针
ListIterator(const self& it)
{
_node = it._node;
}
// 为了使迭代器可以像指针一样去使用,需要重载 operator*() 和 operator->()
// 重载解引用运算符,这里就体现了模板的好处:Ref 可以是 const(只读) ,也可以是可读可写
Ref operator*()
{
return _node->_val;
}
// 重载->运算符
Ptr operator->()
{
return &_node->_val;
}
// == 和 != 运算符
bool operator==(const self& s) const
{
return s._node == _node;
}
bool operator!=(const self& s) const
{
return s._node != _node;
}
// 重载++,实现指针的移动
self& operator++()
{
_node = _node->_next;
return *this;
}
// 后置++
self operator++(int)
{
self tmp(*this);
_node = _node->_next;
return tmp;
}
// 重载--
self& operator--()
{
_node = _node->_pre;
return *this;
}
self operator--(int)
{
self tmp(*this);
_node = _node->_pre;
return tmp;
}
private:
// 迭代器是对指针的封装
node _node;
};
template
class list
{
typedef ListNode node;
// 体现模板的好处,不用再声明一份 const 的迭代器
typedef ListIterator iterator;
typedef ListIterator const_iterator;
private:
// 哨兵节点
node* _head;
public:
// 返回第一个有效元素的位置
iterator begin()
{
return iterator(_head->_next);
}
// 返回最后一个有效元素的下一个位置
iterator end()
{
return iterator(_head);
}
// const 对象调用
const_iterator begin() const
{
return const_iterator(_head->_next);
}
const_iterator end() const
{
return const_iterator(_head);
}
// 判断 list 是否为空
bool empty()
{
return begin() == end();
}
// 插入一个节点
void insert(iterator pos, const T& x)
{
if (pos._node == nullptr)
throw new _exception{ 0, "索引错误" };
node* newNode = new node(x);
node* cur = pos._node;
node* pre = cur->_pre;
pre->_next = newNode;;
newNode->_pre = pre;
newNode->_next = cur;
cur->_pre = newNode;
}
void push_back(const T& x)
{
insert(end(), x);
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
// 删除节点
iterator erase(iterator pos)
{
if (pos == nullptr || pos == end())
throw new _exception{ 0, "索引错误" };
node* pre = pos._node->_pre;
node* next = pos._node->_next;
pre->_next = next;
next->_pre = pre;
delete pos._node
return iterator(next);
}
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it++);
}
}
// 构造函数,构造双向带头链表
list()
{
_head = new node;
_head->_next = _head;
_head->_pre = _head;
}
// 拷贝构造函数
list(const list _list)
{
_head = new node;
_head->_next = _head;
_head->_pre = _head;
for (auto& e : _list)
{
push_back(e);
}
}
// 析构函数
~list()
{
clear();
delete _head;
_head = nullptr;
}
// 拷贝构造
list& operator=(list _list)
{
swap(_head, _list._head);
return *this;
}
int size()
{
int sz = 0;
iterator it = begin();
while (it != end())
{
sz++;
++it;
}
return sz;
}
};
}
list 同样存在迭代器失效问题,与 vector 不同的是,首先进行插入时,list 不会扩容,不会产生野指针,因此插入操作不会导致迭代器失效;
其次,进行删除时 vector 需要挪动元素,导致迭代器指向的元素发生改变,list 进行删除时,则会返回删除元素的下一个位置的迭代器,只会使删除位置的迭代器失效。
stack 是一种容器适配器,底层容器可以是 vector、list等(只要支持 push_back 尾插、pop_back、top 获取栈顶元素和 empty 判空即可),
默认底层容器使用 deque。
模拟实现
#include
#include
namespace Schuyler
{
template<class T, class Container = std::deque<T>>
class stack
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_back();
}
T& top()
{
_con.back();
}
const T& top() const
{
_con.back();
}
bool empty() const
{
_con.empty();
}
size_t size() const
{
return _con.size();
}
private:
Container _con;
};
}
队列也是一种容器适配器,底层容器应该支持:front 返回队头元素引用、back 返回队尾元素引用、push_back 队尾入队列、pop_back 队头出队列
默认情况下底层容器使用 deque。
模拟实现
#include
namespace Schuyler
{
template<class T, class Container = std::deque<T>>
class queue
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_front();
}
T& front()
{
return _con.front();
}
const T& front() const
{
return _con.front();
}
T& back()
{
return _con.back();
}
const T& back() const
{
return _con.back();
}
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
private:
Container _con;
};
}
优先队列
// 声明仿函数
template<class T>
struct less
{
bool operator()(const T& x1, const T& x2)
{
return x1 < x2;
}
};
template<class T>
struct greater
{
bool operator()(const T& x1, const T& x2)
{
return x1 > x2;
}
};
// 优先队列:底层用堆实现,堆就是用数组存储的完全二叉树
template<class T, class Container = std::vector<T>, class Compare = less<T>>
class priority_queue
{
public:
bool empty() const
{
return _con.empty();
}
int size() const
{
return _con.size();
}
T& top()
{
return _con[0];
}
// 堆中任意子节点向上调整
void AjustUp(int child)
{
Compare com;
int parent = child / 2;
while (child > 0)
{
if (com(_con[parent], _con[child]))
{
// 仿函数比较条件为 true,调整父节点和子节点位置
swap(_con[parent], _con[child]);
child = parent;
parent = parent / 2;
}
else
{
// 找到 child 的正确位置,退出循环
break;
}
}
}
void push(const T& x)
{
// 将 x 插入堆的尾部
_con.push_back(x);
// 再向上调整到正确位置
AjustUp(_con.size() - 1);
}
// 用于删除操作的向下调整,将任意一个元素向下调整
void AjustDown(int parent)
{
Compare com;
int child = parent * 2 + 1;
while (child < _con.size())
{
//找到较大的孩子节点
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
++child;
}
// 比较父子节点并调整位置
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
parent = child;
child = child * 2 + 1;
}
else
{
break;
}
}
}
// 删除堆顶元素
void pop()
{
// 堆顶元素和堆的最后一个元素交换位置
swap(_con[0], _con[_con.size() - 1]);
// 删除交换后的堆顶元素
_con.pop_back();
// 调整此时堆顶元素
AjustDown(0);
}
private:
Container _con;
};
额外知识点:堆的建立首先按顺序建立二叉树,其次从最后一个有孩子的节点开始,一层一层往上调。时间复杂度为 O(N)。
为什么使用 deque 作为 stack 和 queue 的底层容器:
模拟实现
#include
// K 模型:只用 Key 作为关键码,关键码就是要查找的值,每个节点只包含 Key
namespace K
{
// 二叉搜索树节点
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
{
_left = nullptr;
_right = nullptr;
_key = key;
}
};
// 二叉搜索树
template <class K>
class BSTree
{
typedef BSTreeNode<K> Node;
private:
// 释放树中的节点,销毁树
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
// 查找 key
Node* _Search(Node* root, const K& key)
{
// 根节点为空或者根节点恰好是要找的,返回 root
if (root == nullptr || root->_key == key)
{
return root;
}
// 根节点大于 key,到左子树中查找
if (root->_key > key)
{
return _Search(root->_left, key);
}
// 根节点小于 key,到右子树中查找
else if (root->_key < key)
{
return _Search(root->_right, key);
}
}
// 拷贝一棵树
Node* _Copy(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
Node* newNode = new Node(root->_key);
// 直到叶子节点开始返回,将节点之间相“连接”
newNode->_left = _Copy(root->_left);
newNode->_right = _Copy(root->_right);
return root;
}
// 插入节点,成功插入返回 true,否则返回 false
bool _Insert(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
// 插入的节点大于 root,往 root 的右子树插
if (root->_key < key)
{
return _Insert(root->_right, key);
}
// 插入的节点小于 root,往 root 的左子树插
else if (root->_key > key)
{
return _Insert(root->_left, key);
}
else
{
return false;
}
}
// 删除节点,成功删除返回 true,否则返回 false
bool _Erase(Node*& root, const K& key)
{
if (root == nullptr)
{
return false;
}
// root 大于要删的元素 ,从 root 的左子树中删除
if (root->_key > key)
{
return _Erase(root->_left, key);
}
// root 小于要删的元素 ,从 root 的右子树中删除
else if (root->_key < key)
{
return _Erase(root->_right, key);
}
// 找到要删除的元素
else
{
if (root->_left == nullptr)
{
Node* del = root;
// 父节点指向删除节点的右孩子节点
root = root->_right;
// 删除节点
delete del;
}
else if (root->_right == nullptr)
{
Node* del = root;
// 父节点指向删除节点的左孩子节点
root = root->_left;
// 删除节点
delete del;
}
else
{
// 要删除节点有两个孩子的情况
// 对删除元素的右子树遍历得到最小值
Node* minRight = root->_right;
while (minRight->_left)
{
minRight = minRight->_left;
}
K min = minRight->_key;
// 删除 root 右子树最小元素
_Erase(root->_left, min);
// 并用最小元素替换删除的元素
root->_key = min;
}
return true;
}
}
public:
// 构造搜索二叉树
BSTree():_root(nullptr)
{}
// 拷贝构造搜索二叉树
BSTree(const BSTree<K>& t)
{
_root = _Copy(t._root);
}
// 赋值重载搜索二叉树
BSTree<K> operator=(BSTree<K> t)
{
swap(_root, t._root);
return *this;
}
// 销毁搜索二叉树
~BSTree()
{
_Destroy(_root);
_root = nullptr;
}
// 查找二叉树中的节点,只对外提供 key 查找,不提供 root
Node* Search(const K& key)
{
_Search(_root, key);
}
// 插入节点,只对外提供 key 查找,不提供 root
bool Insert(const K& key)
{
return _Insert(_root, key);
}
// 删除节点,只对外提供 key 查找,不提供 root
bool Erase(const K& key)
{
return _Erase(_root, key);
}
private:
// 中序遍历,实现按大小顺序打印
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
std::cout << root->_key << " ";
_InOrder(root->_right);
}
public:
void _InOrder()
{
_InOrder(_root);
std::cout << std::endl;
}
private:
Node* _root;
};
}
// KV 模型:二叉树的每个节点是 类型
namespace KV
{
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:
// 插入节点,成功插入返回 true,否则返回 false
bool _Insert(Node*& root, const K& key, const V& value)
{
if (root == nullptr)
{
root = new Node(key, value);
return true;
}
// 插入的节点大于 root,往 root 的右子树插
if (root->_key < key)
{
return _Insert(root->_right, key, value);
}
// 插入的节点小于 root,往 root 的左子树插
else if (root->_key > key)
{
return _Insert(root->_left, key, value);
}
else
{
return false;
}
}
// 查找 key
Node* _Search(Node* root, const K& key)
{
// 根节点为空或者根节点恰好是要找的,返回 root
if (root == nullptr || root->_key == key)
{
return root;
}
// 根节点大于 key,到左子树中查找
if (root->_key > key)
{
return _Search(root->_left, key);
}
// 根节点小于 key,到右子树中查找
else if (root->_key < key)
{
return _Search(root->_right, key);
}
}
// 删除节点,成功删除返回 true,否则返回 false
bool _Erase(Node*& root, const K& key)
{
if (root == nullptr)
{
return false;
}
// root 大于要删的元素 ,从 root 的左子树中删除
if (root->_key > key)
{
return _Erase(root->_left, key);
}
// root 小于要删的元素 ,从 root 的右子树中删除
else if (root->_key < key)
{
return _Erase(root->_right, key);
}
// 找到要删除的元素
else
{
if (root->_left == nullptr)
{
Node* del = root;
// 父节点指向删除节点的右孩子节点
root = root->_right;
// 删除节点
delete del;
}
else if (root->_right == nullptr)
{
Node* del = root;
// 父节点指向删除节点的左孩子节点
root = root->_left;
// 删除节点
delete del;
}
else
{
// 对删除元素的右子树遍历得到最小值
Node* minRight = root->_right;
while (minRight->_left)
{
minRight = minRight->_left;
}
K min_key = minRight->_key;
V min_value = minRight->_value;
// 删除 root 右子树最小元素
_Erase(root->_left, min_key);
// 并用最小元素替换删除的元素
root->_key = min_key;
root->_value = min_value;
}
return true;
}
}
// 拷贝一棵树
Node* _Copy(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
Node* newNode = new Node(root->_key, root->_value);
// 直到叶子节点开始返回,将节点之间相“连接”
newNode->_left = _Copy(root->_left);
newNode->_right = _Copy(root->_right);
return newNode;
}
// 释放树中的节点,销毁树
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
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);
_root = nullptr;
}
private:
Node* _root;
};
}
模拟实现
#include
#include
// AVL 树是一棵特殊的二叉搜索树
namespace Schuyler
{
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
// 平衡因子
int _bf;
// 键值对
std::pair<K, V> _kv;
AVLTreeNode(const std::pair<K, V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_bf(0)
, _kv(kv)
{}
};
template<class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
AVLTree()
:_root(nullptr)
{}
// 析构函数、拷贝构造和赋值运算与二叉搜索树一样
~AVLTree()
{
_Destroy(_root);
_root = nullptr;
}
AVLTree(const AVLTree<K, V>& t)
{
_root = _Copy(t._root);
}
AVLTree<K, V>& operator=(const AVLTree<K, V> t)
{
std::swap(t._root, _root);
return *this;
}
// 查找,非递归形式
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
{
cur = cur->_right;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
// AVL 树是左右子树高度绝对值不能超过 1 的二叉搜索树,
// 每插入一个结点,都要检查平衡性,如果出现不平衡,
// 如果出现不平衡,那么首先要找出最小不平衡子树,然后进行调整
// LL 调整(左孩子的左子树上插入结点导致):右旋
void RotateR(Node* parent)
{
// 左孩子
Node* subL = parent->_left;
// 左孩子的右子树
Node* subLR = subL->_right;
// 1. 调整最小不平衡子树根节点的左孩子
parent->_left = subLR;
// 调整左孩子的右子树的父节点
if (subLR)
subLR->_parent = parent;
// 2. 此时发生右旋
subL->_right = parent;
// 在调整父节点前先保存父节点的父节点
Node* parentParent = parent->_parent;
parent->_parent = subL;
// 3. 如果父节点为根节点,调整根节点
if (_root == parent)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
// 调整最小不平衡子树的根节点的父节点
if (parentParent->_left == parent)
parentParent->_left = subL;
else
parentParent->_right = subL;
subL->_parent = parentParent;
}
// 更新最小不平衡子树的平衡因子
subL->_bf = parent->_bf = 0;
}
// RR 调整(右孩子的右子树上插入结点导致):左旋
void RotateL(Node* parent)
{
// 最小不平衡子树的右孩子
Node* subR = parent->_right;
// 右孩子的左子树
Node* subRL = subR->_left;
// 1.调整最小不平衡子树的右孩子的左子树
// 右边的结点大于根节点,所以“要接在parent->_right”
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
// 2.左旋
subR->_left = parent;
Node* parentParent = parent->_parent;
parent->_parent = subR;
//3. 调整 parentParent
if (_root == parent)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (parentParent->_left == parent)
parentParent->_left = subR;
else
parentParent->_right = subR;
subR->_parent = parentParent;
}
parent->_bf = subR->_bf = 0;
}
// LR 调整(左孩子的右子树上插入结点导致)
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
// 最小不平衡子树的左孩子作为根节点整体左旋
RotateL(parent->_left);
// 最小不平衡子树整体右旋
RotateR(parent);
// 更新平衡因子
if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
subL->_bf = -1;
subLR->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subL->_bf = 0;
subLR->_bf = 0;
}
else
{
assert(false);
}
}
// RL 调整()右孩子的左子树上插入结点导致
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
// 最小不平衡子树的右孩子作为根节点整体左旋
RotateR(parent->_right);
// 最小不平衡子树整体左旋
RotateL(parent);
// 更新平衡因子
if (bf == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
subR->_bf = 0;
subRL->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subR->_bf = 0;
subRL->_bf = 0;
}
else
{
assert(false);
}
}
private:
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
Node* _Copy(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
Node* node = new Node(root->_kv);
node->left = _Copy(root->_left);
node->_right = _Copy(root->_right);
return node;
}
private:
Node* _root;
};
}