B 트 리 의 정의, 삽입, 삭제
B 트 리 는 디스크 나 다른 직접 액세스 하 는 보조 저장 장 치 를 위 한 균형 검색 트 리 입 니 다.
한 그루 의 B 나 무 는 다음 과 같은 성질 을 가 진 뿌리 나무 이다.
1. 각 노드 x 는 아래 의 속성 이 있 습 니 다:
a. x. n, 현재 노드 x 에 저 장 된 키워드 갯 수;
b. x. n 개의 키워드 자체, x. key [1], x. key [2], x. key [x. n] 를 비 내림차 로 저장 합 니 다.
x.key[1]<=x.key[2]<=...<=x.key[x.n]
c. s. leaf 의 불 값 은 x 가 잎 결점 이면 true 이 고 내부 결점 이면 false 입 니 다.
2. 각 내부 결점 x 에는 x. n + 1 개의 아이 결점 을 가리 키 는 지침 도 포함 되 어 있다.잎 결점 에는 아이 가 없고, 그 아이의 지침 은 의미 가 없다.
3. 키워드 x. key [i] 는 각 하위 트 리 에 저 장 된 키워드 의 범 위 를 분할 합 니 다. 만약 k [i] 가 x. c [i] 를 뿌리 로 하 는 하위 트 리 에 저 장 된 키 를 임의로 사용한다 면,
k1<=x.key[i]<=k2<=x.key[2]<=...<=x.key[x.n]<=k[x.n+1]
4. 모든 아이들 의 결점 은 같은 깊이, 즉 나무 높이 h 를 가지 고 있다.
5. 각 아이의 결점 에 포 함 된 키워드 의 개 수 는 지난 번 과 다음 번 이 며, B 트 리 라 고 불 리 는 최소 도수 t 로 고정 적 으로 표시 합 니 다.
a. 뿌리 결점 을 제외 한 모든 결점 은 적어도 t 를 포함해 야 한다 - 1 개의 키 워드 를 가지 고 있 기 때문에 뿌리 결점 을 제외 하고 모든 내부 결점 에는 적어도 t 명의 아이 가 포함 되 어야 합 니 다.
b. 각 노드 는 많아야 2t - 1 개의 키 워드 를 포함 할 수 있 기 때문에 각 내부 노드 는 많아야 2t 명의 아 이 를 포함 할 수 있다.내부 결점 이 2t - 1 키 워드 를 포함 할 때 우 리 는 이 결점 이 가득 하 다 고 말한다.
원본 코드 의 다운로드 링크 를 보 여 줍 니 다:http://download.csdn.net/detail/sky453589103/9041779
B 트 리 의 삽입 동작:
B 트 리 의 삽입 작업 을 진행 할 때 삽 입 된 노드 의 키워드 개수 가 2t - 1 을 초과 하 는 것 을 방지 해 야 합 니 다.만 결점 을 삽입 하려 면 분열 작업 을 해 야 한다.
전체 결점 을 각각 t - 1 개의 결점 을 포함 하 는 두 개의 결점 과 중간 에 있 는 키워드 로 나 누 어 줍 니 다. (아 이 를 잊 지 마 세 요.)
알고리즘 서론 에 서 는 편도 알고리즘 으로 분열 작업 을 합 니 다 (편도 알고리즘: 나무의 뿌리 부터 아래로 내 려 가 고 위로 돌아 가 는 작업 이 없습니다).
뿌리 부터 삽입 하고 길 을 따라 만 나 는 모든 만 결점 을 분열 시 키 면 삽 입 된 결점 이 만 결점 이 아니 라 는 것 을 보장 한다.
뿌리 결점 이 만 결점 일 때 는 뿌리 결점 을 분열 시 켜 새로운 뿌리 를 만들어 야 한다.
bool BSubTree::Insert(const KeyType key) {
BSubTreeNodePtr r = _root;
if (r->_MaxChildNum - 1 == r->_n) {
BSubTreeNodePtr s = new BSubTreeNode(r->_MaxChildNum);
s->Init();
_root = s;
s->_isleaf = false;
s->_child[0] = r;
Split(s, 0);
return Insert_notfull(s, key);
} else {
return Insert_notfull(r ,key);
}
return false;
}
삽입 작업 의 보조 작업 은 루트 노드 에 삽입 되 지 않 았 을 때 이 보조 작업 으로 재 귀적 으로 삽입 해 야 합 니 다.
bool BSubTree::Insert_notfull(BSubTreeNodePtr pnode, const KeyType key) {
unsigned int i = pnode->_n - 1;
if (true == pnode->_isleaf) {
// key
// , 。
while (i >= 0 && key < pnode->_key[i]){
pnode->_key[i + 1] = pnode->_key[i];
--i;
}
pnode->_key[i + 1] = key;
++pnode->_n;
return true;
} else {
while (i >= 0 && key < pnode->_key[i]) {
--i;
}
// ,pnode->_key[i - 1] <= key <= pnode->_key[i]
// key <= pnode->_key[i] <= pnode->_child[i + 1]->key[0]<=
// pnode->_child[i + 1]->_key[pnode->_child[i]->_n - 1] <= pnode->key[i + 1]
++i;
if (pnode->_MaxChildNum - 1 == pnode->_child[i]->_n) {
// key
// key _key[i] _key[i]
Split(pnode, i);
// i , pnode->_key[i - 1] <= key <= pnode->_key[i]
if(key > pnode->_key[i]) {
++i;
}
}
return Insert_notfull(pnode->_child[i], key);
}
B 나무의 분열 동작:
B 트 리 의 분열 작업 은 만 결점 의 후반 부 (t - 1 키워드, t 아이) 를 새로운 결점 에 직접 붙 이 고 중간 결점 (제 t 키워드, 첫 번 째 부터) 을 만 결점 의 부 결점 으로 옮 기 는 것 이다.시간 복잡 도 는 O (n) 이다.
BSubTreeNodePtr rightchild = new BSubTreeNode(pnode->_MaxChildNum);
if (false == rightchild->Init()) {
return false;
}
BSubTreeNodePtr leftchild = pnode->_child[index];
unsigned int t = leftchild->_MaxChildNum / 2;
rightchild->_isleaf = leftchild->_isleaf;
rightchild->_n = t - 1;
// leftchild, leftchild rightchild
for (unsigned int j = 0; j < t - 1; ++j) {
rightchild->_key[j] = leftchild->_key[j + t];
}
if (!leftchild->_isleaf) {
for (unsigned int j = 0; j < t; ++j) {
rightchild->_child[j] = leftchild->_child[j + t];
}
}
leftchild->_n = t - 1;
// index + 1 , pnode->key[index]
// pnode->_child[index + 2] = pnode->nodep[index+ 1]
for (unsigned int j = pnode->_n; j > index; --j) {
pnode->_child[j + 1] = pnode->_child[j];
}
pnode->_child[index + 1] = rightchild;
// index , pnode->key[index]
// pnode->_key[index + 1] = pnode->_key[index]
for (unsigned int j = pnode->_n - 1; j > index - 1; --j) {
pnode->_key[j + 1] = pnode->_key[j];
}
// 。
pnode->_key[index] = leftchild->_key[t - 1];
++pnode->_n;
return true;
}
B 트 리 삭제 동작:
B 트 리 의 삭제 작업 은 비교적 복잡 하 다.
B 트 리 의 삭 제 는 다음 세 가지 상황 을 포함한다.
1. 키워드 k 가 잎 노드 x 에 있 으 면 x 에서 삭제 합 니 다.
2. 만약 키워드 k 가 내부 결점 x 에 있다 면:
a. x 의 왼쪽 형제 y 가 적어도 t 개의 키 워드 를 포함 하고 있다 면 y 를 뿌리 로 하 는 하위 트 리 에서 가장 큰 키 워드 를 찾 아 k1 을 재 귀적 으로 삭제 하고 k1 로 k 를 대체 합 니 다.
b. 만약 에 x 의 형제 z 가 적어도 t 개의 키 워드 를 포함한다 면 z 를 뿌리 로 하 는 서브 트 리 에서 가장 작은 키 워드 를 찾 아 k1 을 재 귀적 으로 삭제 하고 k1 로 k 를 대체 합 니 다.
c. 그렇지 않 으 면 좌우 형제 와 키워드 k 를 Y 에 합병 하면 Y 결점 에 2t - 1 개의 키워드 가 포함 되 고 x 도 z 를 가리 키 는 아 이 를 잃 게 된다.x 에서 z 를 가리 키 는 아 이 를 삭제 하고 z 의 메모 리 를 방출 하 며 Y 에서 k 를 재 귀적 으로 삭제 합 니 다.
3 키워드 k 가 현재 내부 노드 x 에 없 으 면 k 를 포함 하 는 하위 트 리 의 뿌리 x. c [i] 를 확인 합 니 다.만약 x. c [i] 의 키워드 개수 가 t - 1 이 라면 다음 두 가지 방법 으로 x. c [i] 에 키 워드 를 추가 해 야 합 니 다.
a. x. [i] 는 t - 1 개의 키워드 만 있 지만 좌우 형제 가 적어도 t 개의 키 워드 를 포함 하고 있다 면 x 중의 한 키 워드 를 x. c [i] 로 내 려 가 x. c [i] 의 좌우 형제 중의 한 키 워드 를 x 로 올 리 고 해당 하 는 아이 지침 도 이동 해 야 합 니 다.
b. x. c [i] 의 좌우 형제 가 t - 1 개의 키워드 만 있다 면 x. c [i] 를 그 중의 한 형제 와 합 쳐 새로운 결점 으로 만 듭 니 다.x 의 키 워드 를 새 노드 로 내 려 가서 아래로 이동 하 는 노드 를 새로운 노드 의 중간 키워드 라 고 합 니 다.
bool BSubTree::Delete(BSubTreeNodePtr pnode, const KeyType key) {
unsigned int i = 0;
unsigned int t = pnode->_MaxChildNum / 2;
for (; i < pnode->_n; ++i) {
if (key >= pnode->_key[i]) {
break;
}
}
if (key == pnode->_key[i]) {
if (true == pnode->_isleaf) {
while (i < pnode->_n - 1) {
pnode->_key[i] = pnode->_key[i + 1];
--pnode->_n;
++i;
}
return true;
} else {
if (pnode->_child[i]->_n > t - 1) {
BSubTreeNodePtr p = pnode;
while (!p->_isleaf) {
p = p->_child[p->_n];
}
pnode->_key[i] = p->_key[p->_n - 1];
return Delete(p, p->_key[p->_n - 1]);
}
else if (pnode->_child[i + 1]->_n > t -1) {
BSubTreeNodePtr p = pnode;
while (!p->_isleaf) {
p = p->_child[0];
}
pnode->_key[i + 1] = p->_key[0];
return Delete(p ,p->_key[0]);
}
else {
// , ?
unsigned int index;
unsigned int j = pnode->_child[i]->_n;
pnode->_child[i]->_key[j] = pnode->_key[i];
++j;
for (index = 0; index < pnode->_child[i + 1]->_n; ++index, ++j) {
pnode->_child[i]->_key[j] = pnode->_child[i + 1]->_key[index];
}
pnode->_child[i]->_n += pnode->_child[i + 1]->_n + 1;
delete pnode->_child[i + 1];
for (index = i; index < pnode->_n - 1; ++index) {
pnode->_key[index] = pnode->_key[index + 1];
pnode->_child[index + 1] = pnode->_child[index + 2];
}
return Delete(pnode->_child[i], key);
}
}
}
else if (false == pnode->_isleaf){
if (pnode->_child[i]->_n > t - 1) {
return Delete(pnode->_child[i], key);
} else {
if (i - 1 >=0 && pnode->_child[i - 1]->_n > t - 1) {
// pnode->_child[i] ,
// pnode->_child[i - 1]->_key[pnode->_child[i - 1]->_n]
for (unsigned int temp = pnode->_child[i]->_n - 1; temp >= 0; --temp) {
pnode->_child[i]->_key[temp + 1] = pnode->_child[i]->_key[temp];
pnode->_child[i]->_child[temp + 2] = pnode->_child[i]->_child[temp + 1];
}
pnode->_child[i]->_child[1] = pnode->_child[i]->_child[0];
pnode->_child[i]->_key[0] = pnode->_key[i];
pnode->_child[i]->_child[0] = pnode->_child[i - 1]->_child[pnode->_child[i - 1]->_n];
++pnode->_child[i]->_n;
pnode->_key[i] = pnode->_child[i - 1]->_key[pnode->_child[i - 1]->_n];
--pnode->_child[i - 1]->_n;
}
else if (pnode->_child[i + 1]->_n > t - 1) {
// pnode->_child[i] ,
// pnode->_child[i + 1]->_key[pnode->_child[i + 1]->_n]
pnode->_child[i]->_key[pnode->_child[i]->_n] = pnode->_key[i];
pnode->_child[i]->_child[pnode->_child[i]->_n + 1] =
pnode->_child[i + 1]->_child[0];
++pnode->_child[i]->_n;
pnode->_key[i] = pnode->_child[i + 1]->_key[0];
for (unsigned int temp = 0; temp < pnode->_child[i + 1]->_n - 1; ++temp) {
pnode->_child[i + 1]->_key[temp] = pnode->_child[i + 1]->_key[temp + 1];
pnode->_child[i + 1]->_child[temp] = pnode->_child[i + 1]->_child[temp + 1];
}
pnode->_child[i + 1]->_child[pnode->_child[i + 1]->_n - 1] =
pnode->_child[i + 1]->_child[pnode->_child[i + 1]->_n];
--pnode->_child[i + 1]->_n;
}
else {
// pnode->_child[i] t - 1
// pnode->_child[i] 。
pnode->_child[i]->_key[pnode->_child[i]->_n] = pnode->_key[i];
pnode->_child[i]->_child[pnode->_child[i]->_n + 1] = pnode->_child[i + 1]->_child[0];
for (unsigned int temp = i; temp < pnode->_n - 1; ++temp) {
pnode->_key[temp] = pnode->_key[temp + 1];
pnode->_child[temp + 1] = pnode->_child[temp + 2];
}
--pnode->_n;
return Delete(pnode->_child[i], key);
}
}
}
else {
return false;
}
return true;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.