⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpp2.cpp

📁 数据库的应用
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#include "Cpp1.cpp"
#include "stdio.h"
#include "stdlib.h"
CNode::CNode()
{
    m_Type = NODE_TYPE_LEAF;
    m_Count = 0;
    m_pFather = NULL;
}
CNode::~CNode()
{
    DeleteChildren();
}
// 获取一个最近的兄弟结点
CNode* CNode::GetBrother(int& flag)
{
    CNode* pFather = GetFather(); 
    if (NULL == pFather)
    {
        return NULL;
    }
    CNode* pBrother = NULL;
    for (int i = 1; i <= pFather->GetCount() + 1; i++)
    {
        // 找到本结点的位置
        if (pFather->GetPointer(i) == this)
        {
            if (i == (pFather->GetCount() + 1))
            {
                pBrother = pFather->GetPointer(i - 1);    // 本身是最后一个指针,只能找前一个指针
                flag = FLAG_LEFT;
            }
            else
            {
                pBrother = pFather->GetPointer(i + 1);    // 优先找后一个指针
                flag = FLAG_RIGHT;
            }
        }
    }
    return pBrother;
}
// 递归删除子结点
void CNode::DeleteChildren()
{
    for (int i = 1; i <= GetCount(); i++)
    {
        CNode * pNode = GetPointer(i);
        if (NULL != pNode)    // 叶子结点没有指针
        {
            pNode->DeleteChildren();
        }
        delete pNode;
    }
}
CInternalNode::CInternalNode()
{
    m_Type = NODE_TYPE_INTERNAL;
    int i = 0;
    for (i = 0; i < MAXNUM_KEY; i++)
    {
        m_Keys[i] = INVALID;
    }
    for (i = 0; i < MAXNUM_POINTER; i++)
    {
        m_Pointers[i] = NULL;
    }
}
CInternalNode::~CInternalNode()
{
    for (int i = 0; i < MAXNUM_POINTER; i++)
    {
        m_Pointers[i] = NULL;
    }
}
// 在中间结点中插入键
bool CInternalNode::Insert(KEY_TYPE value, CNode* pNode)
{
    // 如果中间结点已满,直接返回失败
    if (GetCount() >= MAXNUM_KEY)
    {
        return false;
    }
    int j = 0;
    // 找到要插入键的位置
    for (int i = 0; (value > m_Keys[i]) && ( i < m_Count); i++)
    {
    }
    // 当前位置及其后面的键依次后移,空出当前位置
    for (j = m_Count; j > i; j--)
    {
        m_Keys[j] = m_Keys[j - 1];
    }
    // 当前位置及其后面的指针依次后移
    for (j = m_Count + 1; j > i + 1; j--)
    {
        m_Pointers[j] = m_Pointers[j - 1];
    }
    
    // 把键和指针存入当前位置
    m_Keys[i] = value;
    m_Pointers[i + 1] = pNode;    // 注意是第i+1个指针而不是第i个指针
    pNode->SetFather(this);      // 非常重要
    m_Count++;
    // 返回成功
    return true;
}
// 在中间结点中删除键,以及该键后的指针
bool CInternalNode::Delete(KEY_TYPE key)
{
    for (int i = 0; (key >= m_Keys[i]) && (i < m_Count); i++)
    {
    }
    for (int j = i - 1; j < m_Count - 1; j++)
    {
        m_Keys[j] = m_Keys[j + 1];
    }
    m_Keys[j] = INVALID;
    for (int k = i; k < m_Count; k++)
    {
        m_Pointers[k] = m_Pointers[k + 1];
    }
    m_Pointers[k] = NULL;
    m_Count--;
    return true;
}
/* 分裂中间结点
分裂中间结点和分裂叶子结点完全不同,因为中间结点不仅有2V键,还有2V+1指针,如果单纯地一分为2,指针将无法分配。
因此根据http://www.seanster.com/BplusTree/BplusTree.html,分裂中间结点的算法是:
根据要插入的键key判断:
(1)如果key小于第V个键,则把第V个键提出来,其左右的键分别分到两个结点中
(2)如果key大于第V+1个键,则把第V+1个键提出来,其左右的键分别分到两个结点中
(3)如果key介于第V和V+1个键之间,则把key作为要提出的键,原来的键各分一半到两个结点中
提出来的RetKey作用是便于后续插入到祖先结点
*/
KEY_TYPE CInternalNode::Split(CInternalNode* pNode, KEY_TYPE key)
{
    int i = 0, j = 0;
    
    // 如果要插入的键值在第V和V+1个键值中间,需要翻转一下,因此先处理此情况
    if ((key > this->GetElement(ORDER_V)) && (key < this->GetElement(ORDER_V + 1)))
    {
        // 把第V+1 -- 2V个键移到指定的结点中 
        for (i = ORDER_V + 1; i <= MAXNUM_KEY; i++)
        {
            j++;
            pNode->SetElement(j, this->GetElement(i));
            this->SetElement(i, INVALID);
        }
        // 把第V+2 -- 2V+1个指针移到指定的结点中
        j = 0;
        for (i = ORDER_V + 2; i <= MAXNUM_POINTER; i++)
        {
            j++;
            this->GetPointer(i)->SetFather(pNode);    // 重新设置子结点的父亲
            pNode->SetPointer(j, this->GetPointer(i));
            this->SetPointer(i, INVALID);
        }
        // 设置好Count个数
        this->SetCount(ORDER_V);
        pNode->SetCount(ORDER_V);
        // 把原键值返回
        return key;
    }
    // 以下处理key小于第V个键值或key大于第V+1个键值的情况
    // 判断是提取第V还是V+1个键
    int position = 0;
    if (key < this->GetElement(ORDER_V)) 
    {
        position = ORDER_V;
    }
    else
    {
        position = ORDER_V + 1;
    }
    // 把第position个键提出来,作为新的键值返回
    KEY_TYPE RetKey = this->GetElement(position);
    // 把第position+1 -- 2V个键移到指定的结点中 
    j = 0;
    for (i = position + 1; i <= MAXNUM_KEY; i++)
    {
        j++;
        pNode->SetElement(j, this->GetElement(i));
        this->SetElement(i, INVALID);
    }
    // 把第position+1 -- 2V+1个指针移到指定的结点中(注意指针比键多一个) 
    j = 0;
    for (i = position + 1; i <= MAXNUM_POINTER; i++)
    {
        j++;
        this->GetPointer(i)->SetFather(pNode);    // 重新设置子结点的父亲
        pNode->SetPointer(j, this->GetPointer(i));
        this->SetPointer(i, INVALID);
    }
    // 清除提取出的位置
    this->SetElement(position, INVALID);
    // 设置好Count个数
    this->SetCount(position - 1);
    pNode->SetCount(MAXNUM_KEY - position);

    return RetKey;
}
// 结合结点,把指定中间结点的数据全部剪切到本中间结点
bool CInternalNode::Combine(CNode* pNode)
{
    // 参数检查
    if (this->GetCount() + pNode->GetCount() + 1> MAXNUM_DATA)    // 预留一个新键的位置
    {
        return false;
    }
    
    // 取待合并结点的第一个孩子的第一个元素作为新键值
    KEY_TYPE NewKey = pNode->GetPointer(1)->GetElement(1);
    
    m_Keys[m_Count] = NewKey;
    m_Count++;
    m_Pointers[m_Count] = pNode->GetPointer(1);
    for (int i = 1; i <= pNode->GetCount(); i++)
    {
        m_Keys[m_Count] = pNode->GetElement(i);
        m_Count++;
        m_Pointers[m_Count] = pNode->GetPointer(i+1);
    }
    return true;
}
// 从另一结点移一个元素到本结点
bool CInternalNode::MoveOneElement(CNode* pNode)
{
    // 参数检查
    if (this->GetCount() >= MAXNUM_DATA)
    {
        return false;
    }
    int i,j;

    // 兄弟结点在本结点左边
    if (pNode->GetElement(1) < this->GetElement(1))
    {
        // 先腾出位置
        for (i = m_Count; i > 0; i--)
        {
            m_Keys[i] = m_Keys[i -1];
        }
        for (j = m_Count + 1; j > 0; j--)
        {
            m_Pointers[j] = m_Pointers[j -1];
        }
        // 赋值
        // 第一个键值不是兄弟结点的最后一个键值,而是本结点第一个子结点的第一个元素的值
        m_Keys[0] = GetPointer(1)->GetElement(1);
        // 第一个子结点为兄弟结点的最后一个子结点
        m_Pointers[0] = pNode->GetPointer(pNode->GetCount() + 1);
        
        // 修改兄弟结点
        pNode->SetElement(pNode->GetCount(), INVALID);
        pNode->SetPointer(pNode->GetCount() + 1, INVALID);
    }
    else    // 兄弟结点在本结点右边
    {
        // 赋值
        // 最后一个键值不是兄弟结点的第一个键值,而是兄弟结点第一个子结点的第一个元素的值
        m_Keys[m_Count] = pNode->GetPointer(1)->GetElement(1);
        // 最后一个子结点为兄弟结点的第一个子结点
        m_Pointers[m_Count + 1] = pNode->GetPointer(1);
        
        // 修改兄弟结点
        for (i = 1; i < pNode->GetCount() - 1; i++)
        {
            pNode->SetElement(i, pNode->GetElement(i + 1));
        }
        for (j = 1; j < pNode->GetCount(); j++)
        {
            pNode->SetPointer(j, pNode->GetPointer(j + 1));
        }
    }
    // 设置数目
    this->SetCount(this->GetCount() + 1);
    pNode->SetCount(pNode->GetCount() - 1);
    return true;
}
// 清除叶子结点中的数据
CLeafNode::CLeafNode()
{
    m_Type = NODE_TYPE_LEAF;
    for (int i = 0; i < MAXNUM_DATA; i++)
    {
        m_Datas[i] = INVALID;
    }
    m_pPrevNode = NULL;
    m_pNextNode = NULL;
}
CLeafNode::~CLeafNode()
{
}
// 在叶子结点中插入数据
bool CLeafNode::Insert(KEY_TYPE value)
{
    // 如果叶子结点已满,直接返回失败
    if (GetCount() >= MAXNUM_DATA)
    {
        return false;
    }
    // 找到要插入数据的位置
    for (int i = 0; (value > m_Datas[i]) && ( i < m_Count); i++)
    {
    }
    // 当前位置及其后面的数据依次后移,空出当前位置
    for (int j = m_Count; j > i; j--)
    {
        m_Datas[j] = m_Datas[j - 1];
    }
    // 把数据存入当前位置
    m_Datas[i] = value;
    m_Count++;
    // 返回成功
    return true;
}
bool CLeafNode::Delete(KEY_TYPE value)
{
    bool found = false;
    for (int i = 0; i < m_Count; i++)
    {
        if (value == m_Datas[i])
        {
            found = true;
            break;
        }
    }
    // 如果没有找到,返回失败
    if (false == found)
    {
        return false;
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -