# 从 B 树删除
> 原文: [https://www.programiz.com/dsa/deletion-from-a-b-tree](https://www.programiz.com/dsa/deletion-from-a-b-tree)
#### 在本教程中,您将学习如何从 b 树中删除键。 此外,您还将找到在 C,C++ ,Java 和 Python 中从 B 树中删除键的工作示例。
删除 B 树上的元素包括三个主要事件:**搜索要删除的键存在的节点**,删除键并按需平衡树。
删除树时,可能会发生称为**下溢**的条件。 当节点包含的数量少于其应持有的最小键数时,就会发生下溢。
在研究删除操作之前,应了解以下术语:
1. **有序前驱**
节点左子级上的最大键称为其有序前驱。
2. **有序后继**
节点右子级上的最小键称为其有序后继。
* * *
## 删除操作
在执行以下步骤之前,必须了解有关度为`m`的 B 树的这些事实。
1. 一个节点最多可以有`m`个子节点。 (即 3)
2. 一个节点最多可以包含`m - 1`个键。 (即 2)
3. 一个节点至少应具有`⌈m/2⌉`个子节点。 (即 2)
4. 一个节点(根节点除外)应至少包含`⌈m/2⌉ - 1`键。 (即 1)
B 树中的删除操作主要有三种情况。
### 情况一
要删除的键位于叶子中。 有两种情况。
1. 删除键不会违反节点应持有的最小键数的属性。
在下面的树中,删除 32 不违反上述属性。
![Delete a key from a B-tree](https://img.kancloud.cn/3a/32/3a323fea05f43c4ecf64328cfaf2a24e_1176x930.png "Delete 32 from B-tree")
从 B 树中删除叶子键(32)
2. 键的删除违反了节点应持有的最小键数的属性。 在这种情况下,我们以从左到右的顺序从其直接相邻的兄弟节点借用键。
首先,访问紧邻的左兄弟姐妹。 如果左兄弟节点的键数目超过最小数目,则从该节点借用键。
否则,请检查以从紧邻的右同级节点借用。
在下面的树中,删除 31 将导致上述情况。 让我们从左侧兄弟节点借用一个键。
![Delete a key from a B-tree](https://img.kancloud.cn/19/90/1990c004c86a09938fda2e7642bdfc98_1176x1428.png "Delete 31 from a B-tree")
删除叶子键(31)
如果两个直接同级节点都已经具有最小数量的键,则将该节点与左同级节点或右同级节点合并。 **此合并是通过父节点完成的。**
在上述情况下,删除 30 个结果。
![Delete a key from a B-tree](https://img.kancloud.cn/cd/76/cd76a0c025b2b8e98d00968d4101c542_1176x1428.png "Delete 30 from a B-tree")
删除叶子键(30)
### 情况二
如果要删除的键位于内部节点中,则会发生以下情况。
1. 如果左子节点的键数超过最小数目,则删除的内部节点将替换为有序的前驱节点。
![Deleting an internal node](https://img.kancloud.cn/ca/2d/ca2da8cd79af0537eef3ade03a19b27d_1176x1428.png "Deleting an internal node")
删除内部节点(33)
2. 如果正确的子项超过了最小数目的键,则删除的内部节点将被有序后继替换。
3. 如果任一子项的键数恰好最小,则合并左子项和右子项。
![Deleting an internal node](https://img.kancloud.cn/46/0d/460d1de73bff3ca6d3983d2ccea4d5db_1176x1428.png "Deleting an internal node")
删除内部节点(30)
合并后,如果父节点的键数少于最小数目,则像情况 I 一样查找同级。
### 情况三
在这种情况下,树的高度会缩小。 如果目标键位于内部节点中,并且键的删除导致节点中键的数量减少(即少于所需的最小数量),则寻找有序前驱和有序后继。 如果两个子级都包含最少数量的钥匙,则无法进行借用。 这导致情况二(3),即合并子级。
同样,寻找同胞借用钥匙。 但是,如果同级也只有最少数量的键,则将同级节点与父级合并。 相应地安排子级们(增加顺序)。
![Deleting an internal node](https://img.kancloud.cn/89/5e/895ee8b2c6802976117a8137f6c5f192_1168x930.png "Deleting an internal node")
删除内部节点(10)
* * *
## Python,Java 和 C/C++ 示例
```py
# Deleting a key on a B-tree in Python
# Btree node
class BTreeNode:
def __init__(self, leaf=False):
self.leaf = leaf
self.keys = []
self.child = []
class BTree:
def __init__(self, t):
self.root = BTreeNode(True)
self.t = t
# Insert a key
def insert(self, k):
root = self.root
if len(root.keys) == (2 * self.t) - 1:
temp = BTreeNode()
self.root = temp
temp.child.insert(0, root)
self.split_child(temp, 0)
self.insert_non_full(temp, k)
else:
self.insert_non_full(root, k)
# Insert non full
def insert_non_full(self, x, k):
i = len(x.keys) - 1
if x.leaf:
x.keys.append((None, None))
while i >= 0 and k[0] < x.keys[i][0]:
x.keys[i + 1] = x.keys[i]
i -= 1
x.keys[i + 1] = k
else:
while i >= 0 and k[0] < x.keys[i][0]:
i -= 1
i += 1
if len(x.child[i].keys) == (2 * self.t) - 1:
self.split_child(x, i)
if k[0] > x.keys[i][0]:
i += 1
self.insert_non_full(x.child[i], k)
# Split the child
def split_child(self, x, i):
t = self.t
y = x.child[i]
z = BTreeNode(y.leaf)
x.child.insert(i + 1, z)
x.keys.insert(i, y.keys[t - 1])
z.keys = y.keys[t: (2 * t) - 1]
y.keys = y.keys[0: t - 1]
if not y.leaf:
z.child = y.child[t: 2 * t]
y.child = y.child[0: t - 1]
# Delete a node
def delete(self, x, k):
t = self.t
i = 0
while i < len(x.keys) and k[0] > x.keys[i][0]:
i += 1
if x.leaf:
if i < len(x.keys) and x.keys[i][0] == k[0]:
x.keys.pop(i)
return
return
if i < len(x.keys) and x.keys[i][0] == k[0]:
return self.delete_internal_node(x, k, i)
elif len(x.child[i].keys) >= t:
self.delete(x.child[i], k)
else:
if i != 0 and i + 2 < len(x.child):
if len(x.child[i - 1].keys) >= t:
self.delete_sibling(x, i, i - 1)
elif len(x.child[i + 1].keys) >= t:
self.delete_sibling(x, i, i + 1)
else:
self.delete_merge(x, i, i + 1)
elif i == 0:
if len(x.child[i + 1].keys) >= t:
self.delete_sibling(x, i, i + 1)
else:
self.delete_merge(x, i, i + 1)
elif i + 1 == len(x.child):
if len(x.child[i - 1].keys) >= t:
self.delete_sibling(x, i, i - 1)
else:
self.delete_merge(x, i, i - 1)
self.delete(x.child[i], k)
# Delete internal node
def delete_internal_node(self, x, k, i):
t = self.t
if x.leaf:
if x.keys[i][0] == k[0]:
x.keys.pop(i)
return
return
if len(x.child[i].keys) >= t:
x.keys[i] = self.delete_predecessor(x.child[i])
return
elif len(x.child[i + 1].keys) >= t:
x.keys[i] = self.delete_successor(x.child[i + 1])
return
else:
self.delete_merge(x, i, i + 1)
self.delete_internal_node(x.child[i], k, self.t - 1)
# Delete the predecessor
def delete_predecessor(self, x):
if x.leaf:
return x.pop()
n = len(x.keys) - 1
if len(x.child[n].keys) >= self.t:
self.delete_sibling(x, n + 1, n)
else:
self.delete_merge(x, n, n + 1)
self.delete_predecessor(x.child[n])
# Delete the successor
def delete_successor(self, x):
if x.leaf:
return x.keys.pop(0)
if len(x.child[1].keys) >= self.t:
self.delete_sibling(x, 0, 1)
else:
self.delete_merge(x, 0, 1)
self.delete_successor(x.child[0])
# Delete resolution
def delete_merge(self, x, i, j):
cnode = x.child[i]
if j > i:
rsnode = x.child[j]
cnode.keys.append(x.keys[i])
for k in range(len(rsnode.keys)):
cnode.keys.append(rsnode.keys[k])
if len(rsnode.child) > 0:
cnode.child.append(rsnode.child[k])
if len(rsnode.child) > 0:
cnode.child.append(rsnode.child.pop())
new = cnode
x.keys.pop(i)
x.child.pop(j)
else:
lsnode = x.child[j]
lsnode.keys.append(x.keys[j])
for i in range(len(cnode.keys)):
lsnode.keys.append(cnode.keys[i])
if len(lsnode.child) > 0:
lsnode.child.append(cnode.child[i])
if len(lsnode.child) > 0:
lsnode.child.append(cnode.child.pop())
new = lsnode
x.keys.pop(j)
x.child.pop(i)
if x == self.root and len(x.keys) == 0:
self.root = new
# Delete the sibling
def delete_sibling(self, x, i, j):
cnode = x.child[i]
if i < j:
rsnode = x.child[j]
cnode.keys.append(x.keys[i])
x.keys[i] = rsnode.keys[0]
if len(rsnode.child) > 0:
cnode.child.append(rsnode.child[0])
rsnode.child.pop(0)
rsnode.keys.pop(0)
else:
lsnode = x.child[j]
cnode.keys.insert(0, x.keys[i - 1])
x.keys[i - 1] = lsnode.keys.pop()
if len(lsnode.child) > 0:
cnode.child.insert(0, lsnode.child.pop())
# Print the tree
def print_tree(self, x, l=0):
print("Level ", l, " ", len(x.keys), end=":")
for i in x.keys:
print(i, end=" ")
print()
l += 1
if len(x.child) > 0:
for i in x.child:
self.print_tree(i, l)
def main():
B = BTree(3)
for i in range(10):
B.insert((i, 2 * i))
B.print_tree(B.root)
B.delete(B.root, (8,))
print("\n")
B.print_tree(B.root)
```
```java
// Inserting a key on a B-tree in Java
import java.util.Stack;
public class BTree {
private int T;
public class Node {
int n;
int key[] = new int[2 * T - 1];
Node child[] = new Node[2 * T];
boolean leaf = true;
public int Find(int k) {
for (int i = 0; i < this.n; i++) {
if (this.key[i] == k) {
return i;
}
}
return -1;
};
}
public BTree(int t) {
T = t;
root = new Node();
root.n = 0;
root.leaf = true;
}
private Node root;
// Search the key
private Node Search(Node x, int key) {
int i = 0;
if (x == null)
return x;
for (i = 0; i < x.n; i++) {
if (key < x.key[i]) {
break;
}
if (key == x.key[i]) {
return x;
}
}
if (x.leaf) {
return null;
} else {
return Search(x.child[i], key);
}
}
// Split function
private void Split(Node x, int pos, Node y) {
Node z = new Node();
z.leaf = y.leaf;
z.n = T - 1;
for (int j = 0; j < T - 1; j++) {
z.key[j] = y.key[j + T];
}
if (!y.leaf) {
for (int j = 0; j < T; j++) {
z.child[j] = y.child[j + T];
}
}
y.n = T - 1;
for (int j = x.n; j >= pos + 1; j--) {
x.child[j + 1] = x.child[j];
}
x.child[pos + 1] = z;
for (int j = x.n - 1; j >= pos; j--) {
x.key[j + 1] = x.key[j];
}
x.key[pos] = y.key[T - 1];
x.n = x.n + 1;
}
// Insert the key
public void Insert(final int key) {
Node r = root;
if (r.n == 2 * T - 1) {
Node s = new Node();
root = s;
s.leaf = false;
s.n = 0;
s.child[0] = r;
Split(s, 0, r);
_Insert(s, key);
} else {
_Insert(r, key);
}
}
// Insert the node
final private void _Insert(Node x, int k) {
if (x.leaf) {
int i = 0;
for (i = x.n - 1; i >= 0 && k < x.key[i]; i--) {
x.key[i + 1] = x.key[i];
}
x.key[i + 1] = k;
x.n = x.n + 1;
} else {
int i = 0;
for (i = x.n - 1; i >= 0 && k < x.key[i]; i--) {
}
;
i++;
Node tmp = x.child[i];
if (tmp.n == 2 * T - 1) {
Split(x, i, tmp);
if (k > x.key[i]) {
i++;
}
}
_Insert(x.child[i], k);
}
}
public void Show() {
Show(root);
}
private void Remove(Node x, int key) {
int pos = x.Find(key);
if (pos != -1) {
if (x.leaf) {
int i = 0;
for (i = 0; i < x.n && x.key[i] != key; i++) {
}
;
for (; i < x.n; i++) {
if (i != 2 * T - 2) {
x.key[i] = x.key[i + 1];
}
}
x.n--;
return;
}
if (!x.leaf) {
Node pred = x.child[pos];
int predKey = 0;
if (pred.n >= T) {
for (;;) {
if (pred.leaf) {
System.out.println(pred.n);
predKey = pred.key[pred.n - 1];
break;
} else {
pred = pred.child[pred.n];
}
}
Remove(pred, predKey);
x.key[pos] = predKey;
return;
}
Node nextNode = x.child[pos + 1];
if (nextNode.n >= T) {
int nextKey = nextNode.key[0];
if (!nextNode.leaf) {
nextNode = nextNode.child[0];
for (;;) {
if (nextNode.leaf) {
nextKey = nextNode.key[nextNode.n - 1];
break;
} else {
nextNode = nextNode.child[nextNode.n];
}
}
}
Remove(nextNode, nextKey);
x.key[pos] = nextKey;
return;
}
int temp = pred.n + 1;
pred.key[pred.n++] = x.key[pos];
for (int i = 0, j = pred.n; i < nextNode.n; i++) {
pred.key[j++] = nextNode.key[i];
pred.n++;
}
for (int i = 0; i < nextNode.n + 1; i++) {
pred.child[temp++] = nextNode.child[i];
}
x.child[pos] = pred;
for (int i = pos; i < x.n; i++) {
if (i != 2 * T - 2) {
x.key[i] = x.key[i + 1];
}
}
for (int i = pos + 1; i < x.n + 1; i++) {
if (i != 2 * T - 1) {
x.child[i] = x.child[i + 1];
}
}
x.n--;
if (x.n == 0) {
if (x == root) {
root = x.child[0];
}
x = x.child[0];
}
Remove(pred, key);
return;
}
} else {
for (pos = 0; pos < x.n; pos++) {
if (x.key[pos] > key) {
break;
}
}
Node tmp = x.child[pos];
if (tmp.n >= T) {
Remove(tmp, key);
return;
}
if (true) {
Node nb = null;
int devider = -1;
if (pos != x.n && x.child[pos + 1].n >= T) {
devider = x.key[pos];
nb = x.child[pos + 1];
x.key[pos] = nb.key[0];
tmp.key[tmp.n++] = devider;
tmp.child[tmp.n] = nb.child[0];
for (int i = 1; i < nb.n; i++) {
nb.key[i - 1] = nb.key[i];
}
for (int i = 1; i <= nb.n; i++) {
nb.child[i - 1] = nb.child[i];
}
nb.n--;
Remove(tmp, key);
return;
} else if (pos != 0 && x.child[pos - 1].n >= T) {
devider = x.key[pos - 1];
nb = x.child[pos - 1];
x.key[pos - 1] = nb.key[nb.n - 1];
Node child = nb.child[nb.n];
nb.n--;
for (int i = tmp.n; i > 0; i--) {
tmp.key[i] = tmp.key[i - 1];
}
tmp.key[0] = devider;
for (int i = tmp.n + 1; i > 0; i--) {
tmp.child[i] = tmp.child[i - 1];
}
tmp.child[0] = child;
tmp.n++;
Remove(tmp, key);
return;
} else {
Node lt = null;
Node rt = null;
boolean last = false;
if (pos != x.n) {
devider = x.key[pos];
lt = x.child[pos];
rt = x.child[pos + 1];
} else {
devider = x.key[pos - 1];
rt = x.child[pos];
lt = x.child[pos - 1];
last = true;
pos--;
}
for (int i = pos; i < x.n - 1; i++) {
x.key[i] = x.key[i + 1];
}
for (int i = pos + 1; i < x.n; i++) {
x.child[i] = x.child[i + 1];
}
x.n--;
lt.key[lt.n++] = devider;
for (int i = 0, j = lt.n; i < rt.n + 1; i++, j++) {
if (i < rt.n) {
lt.key[j] = rt.key[i];
}
lt.child[j] = rt.child[i];
}
lt.n += rt.n;
if (x.n == 0) {
if (x == root) {
root = x.child[0];
}
x = x.child[0];
}
Remove(lt, key);
return;
}
}
}
}
public void Remove(int key) {
Node x = Search(root, key);
if (x == null) {
return;
}
Remove(root, key);
}
public void Task(int a, int b) {
Stack<Integer> st = new Stack<>();
FindKeys(a, b, root, st);
while (st.isEmpty() == false) {
this.Remove(root, st.pop());
}
}
private void FindKeys(int a, int b, Node x, Stack<Integer> st) {
int i = 0;
for (i = 0; i < x.n && x.key[i] < b; i++) {
if (x.key[i] > a) {
st.push(x.key[i]);
}
}
if (!x.leaf) {
for (int j = 0; j < i + 1; j++) {
FindKeys(a, b, x.child[j], st);
}
}
}
public boolean Contain(int k) {
if (this.Search(root, k) != null) {
return true;
} else {
return false;
}
}
// Show the node
private void Show(Node x) {
assert (x == null);
for (int i = 0; i < x.n; i++) {
System.out.print(x.key[i] + " ");
}
if (!x.leaf) {
for (int i = 0; i < x.n + 1; i++) {
Show(x.child[i]);
}
}
}
public static void main(String[] args) {
BTree b = new BTree(3);
b.Insert(8);
b.Insert(9);
b.Insert(10);
b.Insert(11);
b.Insert(15);
b.Insert(20);
b.Insert(17);
b.Show();
b.Remove(10);
System.out.println();
b.Show();
}
}
```
```c
// Deleting a key from a B-tree in C
#include <stdio.h>
#include <stdlib.h>
#define MAX 3
#define MIN 2
struct BTreeNode {
int item[MAX + 1], count;
struct BTreeNode *linker[MAX + 1];
};
struct BTreeNode *root;
// Node creation
struct BTreeNode *createNode(int item, struct BTreeNode *child) {
struct BTreeNode *newNode;
newNode = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));
newNode->item[1] = item;
newNode->count = 1;
newNode->linker[0] = root;
newNode->linker[1] = child;
return newNode;
}
// Add value to the node
void addValToNode(int item, int pos, struct BTreeNode *node,
struct BTreeNode *child) {
int j = node->count;
while (j > pos) {
node->item[j + 1] = node->item[j];
node->linker[j + 1] = node->linker[j];
j--;
}
node->item[j + 1] = item;
node->linker[j + 1] = child;
node->count++;
}
// Split the node
void splitNode(int item, int *pval, int pos, struct BTreeNode *node,
struct BTreeNode *child, struct BTreeNode **newNode) {
int median, j;
if (pos > MIN)
median = MIN + 1;
else
median = MIN;
*newNode = (struct BTreeNode *)malloc(sizeof(struct BTreeNode));
j = median + 1;
while (j <= MAX) {
(*newNode)->item[j - median] = node->item[j];
(*newNode)->linker[j - median] = node->linker[j];
j++;
}
node->count = median;
(*newNode)->count = MAX - median;
if (pos <= MIN) {
addValToNode(item, pos, node, child);
} else {
addValToNode(item, pos - median, *newNode, child);
}
*pval = node->item[node->count];
(*newNode)->linker[0] = node->linker[node->count];
node->count--;
}
// Set the value in the node
int setValueInNode(int item, int *pval,
struct BTreeNode *node, struct BTreeNode **child) {
int pos;
if (!node) {
*pval = item;
*child = NULL;
return 1;
}
if (item < node->item[1]) {
pos = 0;
} else {
for (pos = node->count;
(item < node->item[pos] && pos > 1); pos--)
;
if (item == node->item[pos]) {
printf("Duplicates not allowed\n");
return 0;
}
}
if (setValueInNode(item, pval, node->linker[pos], child)) {
if (node->count < MAX) {
addValToNode(*pval, pos, node, *child);
} else {
splitNode(*pval, pval, pos, node, *child, child);
return 1;
}
}
return 0;
}
// Insertion operation
void insertion(int item) {
int flag, i;
struct BTreeNode *child;
flag = setValueInNode(item, &i, root, &child);
if (flag)
root = createNode(i, child);
}
// Copy the successor
void copySuccessor(struct BTreeNode *myNode, int pos) {
struct BTreeNode *dummy;
dummy = myNode->linker[pos];
for (; dummy->linker[0] != NULL;)
dummy = dummy->linker[0];
myNode->item[pos] = dummy->item[1];
}
// Remove the value
void removeVal(struct BTreeNode *myNode, int pos) {
int i = pos + 1;
while (i <= myNode->count) {
myNode->item[i - 1] = myNode->item[i];
myNode->linker[i - 1] = myNode->linker[i];
i++;
}
myNode->count--;
}
// Do right shift
void rightShift(struct BTreeNode *myNode, int pos) {
struct BTreeNode *x = myNode->linker[pos];
int j = x->count;
while (j > 0) {
x->item[j + 1] = x->item[j];
x->linker[j + 1] = x->linker[j];
}
x->item[1] = myNode->item[pos];
x->linker[1] = x->linker[0];
x->count++;
x = myNode->linker[pos - 1];
myNode->item[pos] = x->item[x->count];
myNode->linker[pos] = x->linker[x->count];
x->count--;
return;
}
// Do left shift
void leftShift(struct BTreeNode *myNode, int pos) {
int j = 1;
struct BTreeNode *x = myNode->linker[pos - 1];
x->count++;
x->item[x->count] = myNode->item[pos];
x->linker[x->count] = myNode->linker[pos]->linker[0];
x = myNode->linker[pos];
myNode->item[pos] = x->item[1];
x->linker[0] = x->linker[1];
x->count--;
while (j <= x->count) {
x->item[j] = x->item[j + 1];
x->linker[j] = x->linker[j + 1];
j++;
}
return;
}
// Merge the nodes
void mergeNodes(struct BTreeNode *myNode, int pos) {
int j = 1;
struct BTreeNode *x1 = myNode->linker[pos], *x2 = myNode->linker[pos - 1];
x2->count++;
x2->item[x2->count] = myNode->item[pos];
x2->linker[x2->count] = myNode->linker[0];
while (j <= x1->count) {
x2->count++;
x2->item[x2->count] = x1->item[j];
x2->linker[x2->count] = x1->linker[j];
j++;
}
j = pos;
while (j < myNode->count) {
myNode->item[j] = myNode->item[j + 1];
myNode->linker[j] = myNode->linker[j + 1];
j++;
}
myNode->count--;
free(x1);
}
// Adjust the node
void adjustNode(struct BTreeNode *myNode, int pos) {
if (!pos) {
if (myNode->linker[1]->count > MIN) {
leftShift(myNode, 1);
} else {
mergeNodes(myNode, 1);
}
} else {
if (myNode->count != pos) {
if (myNode->linker[pos - 1]->count > MIN) {
rightShift(myNode, pos);
} else {
if (myNode->linker[pos + 1]->count > MIN) {
leftShift(myNode, pos + 1);
} else {
mergeNodes(myNode, pos);
}
}
} else {
if (myNode->linker[pos - 1]->count > MIN)
rightShift(myNode, pos);
else
mergeNodes(myNode, pos);
}
}
}
// Delete a value from the node
int delValFromNode(int item, struct BTreeNode *myNode) {
int pos, flag = 0;
if (myNode) {
if (item < myNode->item[1]) {
pos = 0;
flag = 0;
} else {
for (pos = myNode->count; (item < myNode->item[pos] && pos > 1); pos--)
;
if (item == myNode->item[pos]) {
flag = 1;
} else {
flag = 0;
}
}
if (flag) {
if (myNode->linker[pos - 1]) {
copySuccessor(myNode, pos);
flag = delValFromNode(myNode->item[pos], myNode->linker[pos]);
if (flag == 0) {
printf("Given data is not present in B-Tree\n");
}
} else {
removeVal(myNode, pos);
}
} else {
flag = delValFromNode(item, myNode->linker[pos]);
}
if (myNode->linker[pos]) {
if (myNode->linker[pos]->count < MIN)
adjustNode(myNode, pos);
}
}
return flag;
}
// Delete operaiton
void delete (int item, struct BTreeNode *myNode) {
struct BTreeNode *tmp;
if (!delValFromNode(item, myNode)) {
printf("Not present\n");
return;
} else {
if (myNode->count == 0) {
tmp = myNode;
myNode = myNode->linker[0];
free(tmp);
}
}
root = myNode;
return;
}
void searching(int item, int *pos, struct BTreeNode *myNode) {
if (!myNode) {
return;
}
if (item < myNode->item[1]) {
*pos = 0;
} else {
for (*pos = myNode->count;
(item < myNode->item[*pos] && *pos > 1); (*pos)--)
;
if (item == myNode->item[*pos]) {
printf("%d present in B-tree", item);
return;
}
}
searching(item, pos, myNode->linker[*pos]);
return;
}
void traversal(struct BTreeNode *myNode) {
int i;
if (myNode) {
for (i = 0; i < myNode->count; i++) {
traversal(myNode->linker[i]);
printf("%d ", myNode->item[i + 1]);
}
traversal(myNode->linker[i]);
}
}
int main() {
int item, ch;
insertion(8);
insertion(9);
insertion(10);
insertion(11);
insertion(15);
insertion(16);
insertion(17);
insertion(18);
insertion(20);
insertion(23);
traversal(root);
delete (20, root);
printf("\n");
traversal(root);
}
```
```cpp
// Deleting a key from a B-tree in C++
#include <iostream>
using namespace std;
class BTreeNode {
int *keys;
int t;
BTreeNode **C;
int n;
bool leaf;
public:
BTreeNode(int _t, bool _leaf);
void traverse();
int findKey(int k);
void insertNonFull(int k);
void splitChild(int i, BTreeNode *y);
void deletion(int k);
void removeFromLeaf(int idx);
void removeFromNonLeaf(int idx);
int getPredecessor(int idx);
int getSuccessor(int idx);
void fill(int idx);
void borrowFromPrev(int idx);
void borrowFromNext(int idx);
void merge(int idx);
friend class BTree;
};
class BTree {
BTreeNode *root;
int t;
public:
BTree(int _t) {
root = NULL;
t = _t;
}
void traverse() {
if (root != NULL)
root->traverse();
}
void insertion(int k);
void deletion(int k);
};
// B tree node
BTreeNode::BTreeNode(int t1, bool leaf1) {
t = t1;
leaf = leaf1;
keys = new int[2 * t - 1];
C = new BTreeNode *[2 * t];
n = 0;
}
// Find the key
int BTreeNode::findKey(int k) {
int idx = 0;
while (idx < n && keys[idx] < k)
++idx;
return idx;
}
// Deletion operation
void BTreeNode::deletion(int k) {
int idx = findKey(k);
if (idx < n && keys[idx] == k) {
if (leaf)
removeFromLeaf(idx);
else
removeFromNonLeaf(idx);
} else {
if (leaf) {
cout << "The key " << k << " is does not exist in the tree\n";
return;
}
bool flag = ((idx == n) ? true : false);
if (C[idx]->n < t)
fill(idx);
if (flag && idx > n)
C[idx - 1]->deletion(k);
else
C[idx]->deletion(k);
}
return;
}
// Remove from the leaf
void BTreeNode::removeFromLeaf(int idx) {
for (int i = idx + 1; i < n; ++i)
keys[i - 1] = keys[i];
n--;
return;
}
// Delete from non leaf node
void BTreeNode::removeFromNonLeaf(int idx) {
int k = keys[idx];
if (C[idx]->n >= t) {
int pred = getPredecessor(idx);
keys[idx] = pred;
C[idx]->deletion(pred);
}
else if (C[idx + 1]->n >= t) {
int succ = getSuccessor(idx);
keys[idx] = succ;
C[idx + 1]->deletion(succ);
}
else {
merge(idx);
C[idx]->deletion(k);
}
return;
}
int BTreeNode::getPredecessor(int idx) {
BTreeNode *cur = C[idx];
while (!cur->leaf)
cur = cur->C[cur->n];
return cur->keys[cur->n - 1];
}
int BTreeNode::getSuccessor(int idx) {
BTreeNode *cur = C[idx + 1];
while (!cur->leaf)
cur = cur->C[0];
return cur->keys[0];
}
void BTreeNode::fill(int idx) {
if (idx != 0 && C[idx - 1]->n >= t)
borrowFromPrev(idx);
else if (idx != n && C[idx + 1]->n >= t)
borrowFromNext(idx);
else {
if (idx != n)
merge(idx);
else
merge(idx - 1);
}
return;
}
// Borrow from previous
void BTreeNode::borrowFromPrev(int idx) {
BTreeNode *child = C[idx];
BTreeNode *sibling = C[idx - 1];
for (int i = child->n - 1; i >= 0; --i)
child->keys[i + 1] = child->keys[i];
if (!child->leaf) {
for (int i = child->n; i >= 0; --i)
child->C[i + 1] = child->C[i];
}
child->keys[0] = keys[idx - 1];
if (!child->leaf)
child->C[0] = sibling->C[sibling->n];
keys[idx - 1] = sibling->keys[sibling->n - 1];
child->n += 1;
sibling->n -= 1;
return;
}
// Borrow from the next
void BTreeNode::borrowFromNext(int idx) {
BTreeNode *child = C[idx];
BTreeNode *sibling = C[idx + 1];
child->keys[(child->n)] = keys[idx];
if (!(child->leaf))
child->C[(child->n) + 1] = sibling->C[0];
keys[idx] = sibling->keys[0];
for (int i = 1; i < sibling->n; ++i)
sibling->keys[i - 1] = sibling->keys[i];
if (!sibling->leaf) {
for (int i = 1; i <= sibling->n; ++i)
sibling->C[i - 1] = sibling->C[i];
}
child->n += 1;
sibling->n -= 1;
return;
}
// Merge
void BTreeNode::merge(int idx) {
BTreeNode *child = C[idx];
BTreeNode *sibling = C[idx + 1];
child->keys[t - 1] = keys[idx];
for (int i = 0; i < sibling->n; ++i)
child->keys[i + t] = sibling->keys[i];
if (!child->leaf) {
for (int i = 0; i <= sibling->n; ++i)
child->C[i + t] = sibling->C[i];
}
for (int i = idx + 1; i < n; ++i)
keys[i - 1] = keys[i];
for (int i = idx + 2; i <= n; ++i)
C[i - 1] = C[i];
child->n += sibling->n + 1;
n--;
delete (sibling);
return;
}
// Insertion operation
void BTree::insertion(int k) {
if (root == NULL) {
root = new BTreeNode(t, true);
root->keys[0] = k;
root->n = 1;
} else {
if (root->n == 2 * t - 1) {
BTreeNode *s = new BTreeNode(t, false);
s->C[0] = root;
s->splitChild(0, root);
int i = 0;
if (s->keys[0] < k)
i++;
s->C[i]->insertNonFull(k);
root = s;
} else
root->insertNonFull(k);
}
}
// Insertion non full
void BTreeNode::insertNonFull(int k) {
int i = n - 1;
if (leaf == true) {
while (i >= 0 && keys[i] > k) {
keys[i + 1] = keys[i];
i--;
}
keys[i + 1] = k;
n = n + 1;
} else {
while (i >= 0 && keys[i] > k)
i--;
if (C[i + 1]->n == 2 * t - 1) {
splitChild(i + 1, C[i + 1]);
if (keys[i + 1] < k)
i++;
}
C[i + 1]->insertNonFull(k);
}
}
// Split child
void BTreeNode::splitChild(int i, BTreeNode *y) {
BTreeNode *z = new BTreeNode(y->t, y->leaf);
z->n = t - 1;
for (int j = 0; j < t - 1; j++)
z->keys[j] = y->keys[j + t];
if (y->leaf == false) {
for (int j = 0; j < t; j++)
z->C[j] = y->C[j + t];
}
y->n = t - 1;
for (int j = n; j >= i + 1; j--)
C[j + 1] = C[j];
C[i + 1] = z;
for (int j = n - 1; j >= i; j--)
keys[j + 1] = keys[j];
keys[i] = y->keys[t - 1];
n = n + 1;
}
// Traverse
void BTreeNode::traverse() {
int i;
for (i = 0; i < n; i++) {
if (leaf == false)
C[i]->traverse();
cout << " " << keys[i];
}
if (leaf == false)
C[i]->traverse();
}
// Delete Operation
void BTree::deletion(int k) {
if (!root) {
cout << "The tree is empty\n";
return;
}
root->deletion(k);
if (root->n == 0) {
BTreeNode *tmp = root;
if (root->leaf)
root = NULL;
else
root = root->C[0];
delete tmp;
}
return;
}
int main() {
BTree t(3);
t.insertion(8);
t.insertion(9);
t.insertion(10);
t.insertion(11);
t.insertion(15);
t.insertion(16);
t.insertion(17);
t.insertion(18);
t.insertion(20);
t.insertion(23);
cout << "The B-tree is: ";
t.traverse();
t.deletion(20);
cout << "\nThe B-tree is: ";
t.traverse();
}
```
* * *
## 删除复杂度
最佳情况时间复杂度:`Θ(log n)`
平均情况空间复杂度:`Θ(n)`
最坏情况的空间复杂度:`Θ(n)`
- Programiz C 语言教程
- C 简介
- C 关键字和标识符
- C 变量,常量和字面值
- C 数据类型
- C 输入输出(I/O)
- C 编程运算符
- C 简单示例
- C 流程控制
- C if...else语句
- C for循环
- C while和do...while循环
- C break和continue
- C switch语句
- C goto声明
- C 控制流程示例
- C 函数
- C 函数
- C 用户定义的函数
- C 编程中用户定义函数的类型
- C 递归
- C 存储类
- C 函数示例
- C 数组
- C 数组
- C 多维数组
- 将数组传递给 C 中的函数
- C 编程指针
- C 指针
- 数组和指针之间的关系
- C 按引用调用:使用指针
- C 动态内存分配
- C 数组和指针示例
- C 字符串
- C 编程字符串
- 使用库函数进行 C 编程中的字符串操作
- C 编程中的字符串示例
- 结构与联合
- 结构
- 结构和指针
- C 结构与函数
- C 联合
- C 结构示例
- C 文件
- C 文件处理
- C 文件示例
- 其他主题
- 枚举
- C 预处理器和宏
- C 标准库函数
- C 示例
- C 程序:打印金字塔和图案
- C 程序:检查数字是否为质数
- C 程序:检查数字是否为回文
- C 程序:HelloWorld
- C 程序:打印整数(由用户输入)
- C 程序:相加两个整数
- C 程序:将两个浮点数相乘
- C 程序:查找字符的 ASCII 值
- C 程序:商和余数
- C 程序:查找int,float,double和char的大小
- C 程序:long关键字演示
- C 程序:交换两个数字
- C 程序:检查数字是偶数还是奇数
- C 程序:检查字符是元音还是辅音
- C 程序:查找三个数字中最大的数字
- C 程序:查找二次方程的根
- C 程序:检查闰年
- C 程序:检查数字是正数还是负数
- C 程序:检查字符是否为字母
- C 程序:计算自然数之和
- C 程序:查找数字阶乘
- C 程序:生成乘法表
- C 程序:显示斐波那契数列
- C 程序:查找两个数字的 GCD
- C 程序:查找两个数字的 LCM
- C 程序:使用循环从 A 到 Z 显示字符
- C 程序:计算整数中的位数
- C 程序:反转数字
- C 程序:计算数字的幂
- C 程序:显示两个间隔之间的质数
- C 程序:检查阿姆斯特朗数
- C 程序:在两个间隔之间显示阿姆斯特朗数
- C 程序:显示数字因数
- C 程序:使用switch...case制作一个简单的计算器
- C 程序:使用函数显示区间内的质数
- C 程序:使用用户定义的函数检查质数或阿姆斯特朗数
- C 程序:检查一个数字是否可以表示为两个质数之和
- C 程序:使用递归查找自然数之和
- C 程序:使用递归查找数字的阶乘
- C 程序:使用递归查找 GCD
- C 程序:将二进制数转换为十进制,反之亦然
- C 程序:将八进制数转换为十进制,反之亦然
- C 程序:将二进制数转换为八进制,反之亦然
- C 程序:使用递归来反转句子
- C 程序:使用递归计算幂
- C 程序:使用数组计算平均值
- C 程序:查找数组中的最大元素
- C 程序:计算标准差
- C 程序:使用多维数组相加两个矩阵
- C 程序:使用多维数组将两个矩阵相乘
- C 程序:查找矩阵的转置
- C 程序:通过将矩阵传递给函数来将两个矩阵相乘
- C 程序:使用指针访问数组元素
- C 程序:使用按引用调用以循环顺序交换数字
- C 程序:使用动态内存分配查找最大数字
- C 程序:查找字符串中字符的频率
- C 程序:计算元音,辅音等的数量
- C 程序:删除字符串中除字母之外的所有字符
- C 程序:查找字符串的长度
- C 程序:连接两个字符串
- C 程序:不使用strcpy()复制字符串
- C 程序:按字典顺序(字典顺序)对元素进行排序
- C 程序:使用程序存储学生信息
- C 程序:使用结构相加两个距离(以英寸-英尺系统为单位)
- C 程序:通过将结构传递给函数来相加两个复数
- C 程序:计算两个时间段之间的差异
- C 程序:使用结构存储学生信息
- C 程序:在结构中动态存储数据
- C 程序:将句子写入文件
- C 程序:从文件中读取一行并显示它
- C 程序:显示自己的源代码作为输出
- Programiz C++ 教程
- C++ 简介
- C++ 变量,文字和常量
- C++ 数据类型
- C++ 基本输入/输出
- C++ 类型转换
- C++ 运算符
- C++ 注释
- C++ 流控制
- C++ if,if...else和嵌套if...else
- C++ for循环
- C++ while和do...while循环
- C++ break语句
- C++ switch..case语句
- C++ goto语句
- C++ 函数
- C++ 函数
- C++ 中用户定义函数的类型
- C++ 函数重载
- C++ 编程默认参数(参数)
- C++ 存储类
- C++ 递归
- C++ 通过引用返回
- C++ 数组和字符串
- C++ 数组
- C++ 多维数组
- 在 C++ 编程中将数组传递给函数
- C++ 字符串
- C++ 结构
- C++ 结构
- C++ 结构与功能
- C++ 结构指针
- C++ 枚举
- C++ 对象和类
- C++ 类和对象
- C++ 构造器
- 如何通过 C++ 中的函数传递和返回对象?
- C++ 运算符重载
- C++ 指针
- C++ 指针
- C++ 指针和数组
- 通过引用进行 C++ 调用:使用指针[包含示例]
- C++ 内存管理:new和delete
- C++ 继承
- C++ 继承
- C++ 编程中的公共,受保护和私有继承
- C++ 函数覆盖
- C++ 多重,多层和层次继承
- C++ 友元函数和友元类
- C++ 虚函数
- C++ 模板
- C++ 示例
- C++ 程序:HelloWorld
- C++ 程序:检查数字是否为质数
- C++ 程序:创建金字塔和图案
- C++ 程序:加两个数字
- C++ 程序:打印用户输入的数字
- C++ 程序:查找商数和余数
- C++ 程序:在系统中查找int,float,double和char的大小
- C++ 程序:交换两个数字
- C++ 程序:检查数字是偶数还是奇数
- C++ 程序:检查字符是元音还是辅音
- C++ 程序:查找三个数字中最大的数字
- C++ 程序:查找二次方程式的所有根
- C++ 程序:计算自然数之和
- C++ 程序:检查闰年
- C++ 程序:查找阶乘
- C++ 程序:生成乘法表
- C++ 程序:显示斐波那契数列
- C++ 程序:查找 GCD
- C++ 程序:查找 LCM
- C++ 程序:反转数字
- C++ 程序:计算数字的幂
- C++ 程序:递增++和递减--运算符重载
- C++ 程序:使用运算符重载减去复数
- C++ 程序:查找字符的 ASCII 值
- C++ 程序:将两个数相乘
- C++ 程序:检查数字是否为回文
- C++ 程序:显示两个间隔之间的质数
- C++ 程序:检查阿姆斯特朗数
- C++ 程序:显示两个间隔之间的阿姆斯特朗数
- C++ 程序:显示数字的因数
- C++ 程序:使用switch...case的简单的加减乘除计算器
- C++ 程序:使用函数显示两个时间间隔之间的质数
- C++ 程序:通过创建函数来检查质数
- C++ 程序:检查数字是否可以表示为两个质数之和
- C++ 程序:使用递归查找自然数之和
- C++ 程序:使用递归计算数字的阶乘
- C++ 程序:使用递归查找 GCD
- C++ 程序:将二进制数转换为十进制,反之亦然
- C++ 程序:将八进制数转换为十进制,反之亦然
- C++ 程序:将二进制数转换为八进制,反之亦然
- C++ 程序:使用递归来反转句子
- C++ 程序:使用递归计算幂
- C++ 程序:使用数组计算数字平均值
- C++ 程序:查找数组的最大元素
- C++ 程序:计算标准差
- C++ 程序:使用多维数组相加两个矩阵
- C++ 程序:使用多维数组将两个矩阵相乘
- C++ 程序:查找矩阵的转置
- C++ 程序:通过将矩阵传递给函数将两个矩阵相乘
- C++ 程序:使用指针访问数组元素
- C++ 程序:使用引用调用以循环顺序交换数字
- C++ 程序:查找字符串中字符的频率
- C++ 程序:查找字符串中元音,辅音,数字和空白的数量
- C++ 程序:删除字符串中除字母之外的所有字符
- C++ 程序:查找字符串的长度
- C++ 程序:连接两个字符串
- C++ 程序:复制字符串
- C++ 程序:按字典顺序(字典顺序)对元素进行排序
- C++ 程序:在结构中存储学生的信息
- C++ 程序:使用结构相加两个距离(以英寸-英尺为单位)
- C++ 程序:通过将结构传递给函数来添加复数
- C++ 程序:计算两个时间段之间的差异
- C++ 程序:使用结构存储和显示信息
- Programiz C# 教程
- 简介
- C# Hello World - 您的第一个 C# 程序
- C# 关键字和标识符
- C# 变量和(原始)数据类型
- C# 运算符
- C# 基本输入和输出
- C# 表达式,语句和块(带有示例)
- C# 注释
- 流程控制
- C# if,if...else,if...else if和嵌套if语句
- C# for循环
- C# while和do...while循环
- C# foreach循环
- C# switch语句
- C# 三元(?:)运算符
- 其他话题
- C# 按位和移位运算符
- C# 预处理程序指令
- C# 编程中的命名空间
- C# 部分类和部分方法
- Programiz 数据结构和算法教程
- DSA 简介
- 什么是算法?
- 为什么要学习数据结构和算法?
- 渐近分析
- 主定理
- 分治算法
- 数据结构(一)
- 栈
- 队列
- 队列类型
- 循环队列
- 优先队列
- 双端队列
- 数据结构(二)
- 链表
- 链表操作:遍历,插入和删除
- 链表的类型 - 单链,双链和循环链
- 哈希表
- 堆数据结构
- 斐波那契堆
- 减小斐波那契堆上的键和删除节点的操作
- 基于树的 DSA(I)
- 树数据结构
- 树遍历 - 中序,前序和后序
- 满二叉树
- 满二叉树
- 完美二叉树
- 完全二叉树
- 平衡二叉树
- 二叉搜索树(BST)
- AVL 树
- 基于树的 DSA(II)
- B 树
- 插入 B 树
- 从 B 树删除
- B+ 树
- 在 B+ 树上插入
- 从 B+ 树中删除
- 红黑树
- 插入红黑树
- 从红黑树中删除
- 基于图的 DSA
- 图数据结构
- 生成树和最小生成树
- 强连通的组件
- 邻接矩阵
- 邻接表
- DFS 算法
- BFS 算法
- Bellman Ford 算法
- 排序和搜索算法
- 冒泡排序算法
- 选择排序算法
- 插入排序算法
- 归并排序算法
- 快速排序算法
- 计数排序算法
- 基数排序算法
- 桶排序算法
- 堆排序算法
- Shell 排序算法
- 线性搜索
- 二分搜索
- 贪婪算法
- 贪婪算法
- Ford-Fulkerson 算法
- Dijkstra 算法
- Kruskal 算法
- Prim 算法
- 霍夫曼编码
- 动态规划
- 动态规划
- Floyd-Warshall 算法
- 最长公共子序列
- 其他算法
- 回溯算法
- Rabin-Karp 算法
- Programiz Java 教程
- Java 简介
- Java HelloWorld 程序
- Java JDK,JRE 和 JVM
- Java 变量和(原始)数据类型
- Java 运算符
- Java 基本输入和输出
- Java 表达式,语句和块
- Java 注释
- Java 流程控制
- Java if,if...else语句
- Java switch语句
- Java for循环
- Java for-each循环(增强循环)
- Java while和do...while循环
- Java Break语句
- Java continue语句
- Java 数组
- Java 数组
- Java 多维数组
- Java 复制数组
- Java OOP(I)
- Java 类和对象
- Java 方法
- Java 构造器
- Java 字符串
- Java 访问修饰符
- Java this关键字
- Java final关键字
- Java 递归
- Java instanceof
- Java OOP(II)
- Java 继承
- Java 方法覆盖
- Java super
- Java 抽象类和抽象方法
- Java 接口
- Java 多态
- Java 封装
- Java OOP(III)
- Java 嵌套和内部类
- Java 静态嵌套类
- Java 匿名类
- Java 单例
- Java 枚举
- Java 枚举构造器
- Java 枚举字符串
- Java 反射
- Java 异常处理
- Java 异常
- Java 异常处理
- Java throw
- Java 捕获多个异常
- Java try-with-resources
- Java 注解
- Java 注解类型
- Java 日志
- Java 断言
- Java 列表
- Java 集合框架
- Java Collection接口
- Java List接口
- Java ArrayList类
- Java Vector
- Java Stack类
- Java 队列
- Java Queue接口
- Java PriorityQueue
- Java Deque接口
- Java LinkedList
- Java ArrayDeque
- Java BlockingQueue
- Java ArrayBlockingQueue
- Java LinkedBlockingQueue
- Java 映射
- Java Map接口
- Java HashMap
- Java LinkedHashMap
- Java WeakHashMap
- Java EnumMap
- Java SortedMap接口
- Java NavigableMap接口
- Java TreeMap
- Java ConcurrentMap接口
- Java ConcurrentHashMap
- Java 集
- Java Set接口
- Java HashSet类
- Java EnumSet
- Java LinkedHashSet
- Java SortedSet接口
- Java NavigableSet接口
- Java TreeSet
- Java 算法
- Java Iterator接口
- Java ListIterator接口
- Java I/O 流
- Java I/O 流
- Java InputStream类
- Java OutputStream类
- Java FileInputStream类
- Java FileOutputStream类
- Java ByteArrayInputStream类
- Java ByteArrayOutputStream类
- Java ObjectInputStream类
- Java ObjectOutputStream类
- Java BufferedInputStream类
- Java BufferedOutputStream类
- Java PrintStream类
- Java 读取器/写入器
- Java Reader类
- Java Writer类
- Java InputStreamReader类
- Java OutputStreamWriter类
- Java FileReader类
- Java FileWriter类
- Java BufferedReader类
- Java BufferedWriter类
- Java StringReader类
- Java StringWriter类
- Java PrintWriter类
- 其他主题
- Java Scanner类
- Java 类型转换
- Java 自动装箱和拆箱
- Java Lambda 表达式
- Java 泛型
- Java File类
- Java 包装器类
- Java 命令行参数
- Java 实例
- Java 程序:检查数字是否为质数
- Java 程序:显示斐波那契数列
- Java 程序:创建金字塔和图案
- Java 程序:反转数字
- Java 程序:打印整数(由用户输入)
- Java 程序:相加两个整数
- Java 程序:将两个浮点数相乘
- Java 程序:查找字符的 ASCII 值
- Java 程序:计算商数和余数
- Java 程序:交换两个数字
- Java 程序:检查数字是偶数还是奇数
- Java 程序:检查字母是元音还是辅音
- Java 程序:在三个数字中找到最大值
- Java 程序:查找二次方程式的所有根
- Java 程序:检查闰年
- Java 程序:检查数字是正数还是负数
- Java 程序:检查字符是否为字母
- Java 程序:计算自然数之和
- Java 程序:查找数字的阶乘
- Java 程序:生成乘法表
- Java 程序:显示斐波那契数列
- Java 程序:查找两个数字的 GCD
- Java 程序:查找两个数字的 LCM
- Java 程序:使用循环从 A 到 Z 显示字符
- Java 程序:计算整数的位数
- Java 程序:计算数字的幂
- Java 程序:检查数字是否为回文
- Java 程序:检查数字是否为质数
- Java 程序:显示两个时间间隔之间的质数
- Java 程序:检查阿姆斯特朗数
- Java 程序:显示两个间隔之间的阿姆斯特朗数
- Java 程序:使用函数显示间隔之间的质数
- Java 程序:使用函数显示间隔之间的阿姆斯特朗数
- Java 程序:以显示数字的因数
- Java 程序:使用switch...case创建一个简单的计算器
- Java 程序:检查一个数字是否可以表示为两个质数之和
- Java 程序:使用递归查找自然数之和
- Java 程序:使用递归查找数字的阶乘
- Java 程序:使用递归查找 GCD
- Java 程序:将二进制数转换为十进制,反之亦然
- Java 程序:将八进制数转换为十进制,反之亦然
- Java 程序:将二进制数转换为八进制,反之亦然
- Java 程序:使用递归来反转句子
- Java 程序:使用递归来计算幂
- Java 程序:使用数组计算平均值
- Java 程序:查找数组的最大元素
- Java 程序:计算标准差
- Java 程序:使用多维数组相加两个矩阵
- Java 程序:使用多维数组相乘矩阵
- Java 程序:通过将矩阵传递给函数来将两个矩阵相乘
- Java 程序:查找矩阵转置
- Java 程序:查找字符串中字符的频率
- Java 程序:计算句子中元音和辅音的数量
- Java 程序:按字典顺序对元素进行排序
- Java 程序:通过将对象传递给函数来相加两个复数
- Java 程序:计算两个时间段之间的差异
- Java 程序:从字符串中删除所有空格
- Java 程序:打印数组
- Java 程序:将字符串转换为日期
- Java 程序:将数字四舍五入到 n 个小数位
- Java 程序:连接两个数组
- Java 程序:将字符转换为字符串,反之亦然
- Java 程序:检查数组是否包含给定值
- Java 程序:检查字符串是否为空或null
- Java 程序:获取当前日期/时间
- Java 程序:将毫秒转换为分钟和秒
- Java 程序:相加两个日期
- Java 程序:连接两个列表
- Java 程序:将列表(ArrayList)转换为数组,反之亦然
- Java 程序:获取当前工作目录
- Java 程序:将映射(HashMap)转换为列表
- Java 程序:将数组转换为集(HashSet),反之亦然
- Java 程序:将字节数组转换为十六进制
- Java 程序:从文件内容创建字符串
- Java 程序:将文本附加到现有文件
- Java 程序:将栈跟踪转换为字符串
- Java 程序:将文件转换为字节数组,反之亦然
- Java 程序:将InputStream转换为字符串
- Java 程序:将OutputStream转换为字符串
- Java 程序:按字符串值查找枚举
- Java 程序:比较字符串
- Java 程序:按值对映射进行排序
- Java 程序:按属性对自定义对象的ArrayList进行排序
- Java 程序:检查字符串是否为数字
- Java 程序:创建目录
- Java 程序:重命名文件
- Java 程序:列出目录中的文件
- Java 程序:复制文件
- Programiz Kotlin 教程
- Kotlin 简介
- Kotlin HelloWorld - 您的 Kotlin 程序
- Kotlin 变量和原始类型
- Kotlin 运算符
- Kotlin 类型转换
- Kotlin 表达式,语句和块
- Kotlin 注释
- Kotlin 基本输入/输出
- Kotlin 流程控制
- Kotlin if表达式
- Kotlin when表达式
- Kotlin while和do...while循环
- Kotlin for循环
- Kotlin break表达式
- Kotlin continue表达式
- Kotlin 函数
- Kotlin 函数
- Kotlin 中缀函数调用
- Kotlin 默认和命名参数
- Kotlin 递归(递归函数)和尾递归
- Kotlin OOP
- Kotlin 类和对象
- Kotlin 构造器
- Kotlin 获取器和设置器
- Kotlin 继承
- Kotlin 可见性修饰符
- Kotlin 抽象类
- Kotlin 接口
- Kotlin 嵌套和内部类
- Kotlin 数据类
- Kotlin 密封类
- Kotlin 对象声明和表达式
- Kotlin 伴随对象
- Kotlin 扩展函数
- Kotlin 运算符重载
- Kotlin 示例
- Kotlin 程序:获取当前日期/时间
- Kotlin 程序:将列表(ArrayList)转换为Array,反之亦然
- Kotlin 程序:将字符串转换为日期
- Kotlin 程序:按属性对自定义对象的ArrayList进行排序
- Kotlin 程序:打印整数(由用户输入)
- Kotlin 程序:相加两个整数
- Kotlin 程序:将两个浮点数相乘
- Kotlin 程序:查找字符的 ASCII 值
- Kotlin 程序:计算商数和余数
- Kotlin 程序:交换两个数字
- Kotlin 程序:检查数字是偶数还是奇数
- Kotlin 程序:检查字母是元音还是辅音
- Kotlin 程序:在三个数字中找到最大的一个
- Kotlin 程序:查找二次方程的所有根
- Kotlin 程序:检查闰年
- Kotlin 程序:检查数字是正数还是负数
- Kotlin 程序:检查字符是否为字母
- Kotlin 程序:计算自然数之和
- Kotlin 程序:查找数字的阶乘
- Kotlin 程序:生成乘法表
- Kotlin 程序:展示斐波那契数列
- Kotlin 程序:查找两个数字的 GCD
- Kotlin 程序:查找两个数字的 LCM
- Kotlin 程序:使用循环从 A 到 Z 显示字符
- Kotlin 程序:计算整数位数
- Kotlin 程序:反转数字
- Kotlin 程序:计算数字的幂
- Kotlin 程序:检查数字是否为回文
- Kotlin 程序:检查数字是否为质数
- Kotlin 程序:显示两个间隔之间的质数
- Kotlin 程序:检查阿姆斯特朗数
- Kotlin 程序:显示两个间隔之间的阿姆斯特朗数
- Kotlin 程序:使用函数显示间隔之间的质数
- Kotlin 程序:使用函数显示间隔之间的阿姆斯特朗数
- Kotlin 程序:显示数字因数
- Kotlin 程序:使用switch...case制作一个简单的计算器
- Kotlin 程序:检查一个数字是否可以表示为两个质数之和
- Kotlin 程序:使用递归找到自然数之和
- Kotlin 程序:使用递归查找数字的阶乘
- Kotlin 程序:使用递归查找 GCD
- Kotlin 程序:将二进制数转换为十进制,反之亦然
- Kotlin 程序:将八进制数转换为十进制,反之亦然
- Kotlin 程序:将二进制数转换为八进制,反之亦然
- Kotlin 程序:使用递归来反转句子
- Kotlin 程序:使用递归来计算幂
- Kotlin 程序:使用数组计算平均值
- Kotlin 程序:在数组中查找最大的元素
- Kotlin 程序:计算标准差
- Kotlin 程序:使用多维数组相加两个矩阵
- Kotlin 程序:使用多维数组乘以矩阵
- Kotlin 程序:通过将矩阵传递给函数来将两个矩阵相乘
- Kotlin 程序:查找矩阵的转置
- Kotlin 程序:查找字符串中字符的频率
- Kotlin 程序:计算句子中元音和辅音的数量
- Kotlin 程序:按字典顺序(字典顺序)对元素进行排序
- Kotlin 程序:通过将类传递给函数来相加两个复数
- Kotlin 程序:计算两个时间段之间的差异
- Kotlin 程序:创建金字塔和图案
- Kotlin 程序:从字符串中删除所有空格
- Kotlin 程序:打印数组
- Kotlin 程序:将数字四舍五入到 n 个小数位
- Kotlin 程序:连接两个数组
- Kotlin 程序:将字符转换为字符串并反之
- Kotlin 程序:检查数组是否包含给定值
- Kotlin 程序:检查字符串是否为空或null
- Kotlin 程序:将毫秒转换为分钟
- Kotlin 程序:相加两个日期
- Kotlin 程序:连接两个列表
- Kotlin 程序:获取当前工作目录
- Kotlin 程序:将映射(HashMap)转换为列表
- Kotlin 程序:将数组转换为Set(HashSet),反之亦然
- Kotlin 程序:将字节数组转换为十六进制
- Kotlin 程序:从文件内容创建字符串
- Kotlin 程序:将文本附加到现有文件
- Kotlin 程序:将栈跟踪转换为字符串
- Kotlin 程序:将文件转换为字节数组,反之亦然
- Kotlin 程序:将InputStream转换为字符串
- Kotlin 程序:将OutputStream转换为字符串
- Kotlin 程序:通过字符串值查找枚举
- Kotlin 程序:比较字符串
- Kotlin 程序:按值对映射排序
- Kotlin 程序:检查字符串是否为数字
- Programiz Python 教程
- Python 简介
- 如何开始使用 Python?
- Python 关键字和标识符
- Python 语句,缩进和注释
- Python 变量,常量和字面值
- Python 数据类型
- Python 类型转换
- Python 输入,输出和导入
- Python 运算符
- Python 命名空间和范围
- Python 流程控制
- Python if...else语句
- Python for循环
- Python While循环
- Python break和continue
- Python pass语句
- Python 函数
- Python 函数
- Python 函数参数
- Python 递归
- Python 匿名/ Lambda 函数
- Python 全局,局部和非局部变量
- Python global关键字
- Python 模块
- Python 包
- Python 数据类型
- Python 数字,类型转换和数学
- Python 列表
- Python 元组
- Python 字符串
- Python 集
- Python 字典
- Python 文件
- Python 文件 I/O
- Python 目录和文件管理
- Python 错误和内置异常
- Python 使用try,except和finally语句的异常处理
- Python 自定义异常
- Python 对象和类
- Python 面向对象编程
- Python 对象和类
- Python 继承
- Python 多重继承
- Python 运算符重载
- Python 高级主题
- Python 迭代器
- Python 生成器
- Python 闭包
- Python 装饰器
- Python @property装饰器
- Python 正则表达式
- Python 日期时间
- Python 日期时间
- Python strftime()
- Python strptime()
- 如何在 Python 中获取当前日期和时间?
- Python 获取当前时间
- Python 日期时间到时间戳,反之亦然
- Python time模块
- Python sleep()
- Python 示例
- Python 程序:检查质数
- Python 程序:相加两个数字
- Python 程序:查找数字阶乘
- Python 程序:制作一个简单的计算器
- Python 程序:打印 Helloworld
- Python 程序:查找平方根
- Python 程序:计算三角形的面积
- Python 程序:求解二次方程式
- Python 程序:交换两个变量
- Python 程序:生成随机数
- Python 程序:将公里转换为英里
- Python 程序:将摄氏温度转换为华氏温度
- Python 程序:检查数字是正数,负数还是 0
- Python 程序:检查数字是奇数还是偶数
- Python 程序:检查闰年
- Python 程序:在三个数字中找到最大的
- Python 程序:检查质数
- Python 程序:打印一个间隔内的所有质数
- Python 程序:查找数字阶乘
- Python 程序:显示乘法表
- Python 程序:打印斐波那契序列
- Python 程序:检查阿姆斯特朗数
- Python 程序:查找间隔内的阿姆斯特朗数
- Python 程序:查找自然数总和
- Python 程序:使用匿名函数显示 2 的幂
- Python 程序:查找可被另一个数整除的数字
- Python 程序:将十进制转换为二进制,八进制和十六进制
- Python 程序:查找字符的 ASCII 值
- Python 程序:查找 HCF 或 GCD
- Python 程序:查找 LCM
- Python 程序:查找数字的因数
- Python 程序:制作一个简单的计算器
- Python 程序:打乱纸牌
- Python 程序:显示日历
- Python 程序:使用递归显示斐波那契数列
- Python 程序:使用递归查找自然数之和
- Python 程序:使用递归查找数字的阶乘
- Python 程序:使用递归将十进制转换为二进制
- Python 程序:相加两个矩阵
- Python 程序:转置矩阵
- Python 程序:将两个矩阵相乘
- Python 程序:检查字符串是否为回文
- Python 程序:从字符串中删除标点符号
- Python 程序:按字母顺序对单词进行排序
- Python 程序:演示不同的集合操作
- Python 程序:计算每个元音的数量
- Python 程序:合并邮件
- Python 程序:查找图像的大小(分辨率)
- Python 程序:查找文件哈希
- Programiz Swift 教程
- Swift 介绍
- Swift HelloWorld 程序
- Swift 变量,常量和字面值
- Swift 数据类型
- Swift 可选项
- Swift 的字符和字符串
- Swift 基本输入和输出
- Swift 表达式,语句和代码块
- Swift 注释
- Swift 运算符
- Swift 运算符
- Swift 运算符的优先级和关联性
- Swift 三元条件运算符
- Swift 按位和移位运算符
- Seift 流程控制
- Swift if,if...else语句
- switch语句
- Swift for-in循环
- Swift while和repeat...while循环
- Swift 中的嵌套循环
- break语句
- continue语句
- Guard语句
- Swift 集合
- Swift 数组
- Swift 集
- Swift 字典
- Swift 函数
- Swift 函数
- Swift 函数参数和返回值
- Swift 嵌套函数
- Swift 递归
- Swift 范围
- Swift 函数重载
- Swift 进阶
- Swift 闭包
- Swift 类型别名