【问题标题】:Find the k-th smallest element recursively in a B-tree with more than one elements in a node在一个节点中有多个元素的 B 树中递归地找到第 k 个最小的元素
【发布时间】:2018-11-12 20:42:22
【问题描述】:

假设我们有以下 b-tree

我想创建一个算法来找到第 k 个最小的元素。我尝试实现link 中所写的内容,但我发现似乎没有一个解决方案适用于这种树。

到目前为止我已经做到了,这对于最后一个分支的元素运行良好

i <-0
function kthSmallestElement(Node node, int k)
    if(branch[i] != NULL) then
        size<-branch[i].size();
    if(k < size) then
        i++;
        call the function recursively for new branch[i], k
    else if(k > size) then
        k-=size
        i++;
        call the function recursively for new branch[i], k
    else if (k==size) then
        print branch[i]->entry[k-1]
    else
        print brach[i-1]->entry[k-1]
end function

我已经使用 C 实现了算法

#define MAX 4      /* maximum number of keys in node. */
#define MIN 2      /* minimum number of keys in node */

typedef int Key;

typedef struct {
   Key key;
   int value;     /* values can be arbitrary */
} Treeentry;


typedef enum {FALSE, TRUE} Boolean;

typedef struct treenode Treenode;

struct treenode {
  int count;     /* denotes how many keys there are in the node */
    /*
        The entries at each node are kept in an array entry 
          and the pointers in an array branch
    */
  Treeentry entry[MAX+1];
  Treenode *branch[MAX+1];
};

int i = 0;
int size = 0;
void FindKthSmallestElement(Treenode *rootNode, int k){
  if(branch[i] != NULL) //since the node has a child
    size = branch[i] ->count;
    if(k < size){
      i++;
      FindKthSmallestElement(branch[i], k);
    }else if(k > size){
      k-=size;
      i++;
      FindKthSmallestElement(branch[i], k);
    }else if (k==size)
      printf ("%d", branch[i]->entry[k-1].key);
    else
      printf ("%d", brach[i-1]->entry[k-1].key);
}

您能否建议我应该解决什么问题才能为每个第 k 个最小的元素提供有效的输出?我倾向于认为这个问题不能递归解决,因为我们在每个节点中有多个条目。把它变成像link 这样的堆树是明智的吗?

【问题讨论】:

  • 采用普通的b-tree排序算法并取第k个元素有什么问题?
  • 请将其转换为minimal reproducible example,以证明您已取得的成就。
  • 贴出的代码不是C,而是一些伪代码。您说它“对于最后一个分支的元素运行良好”。好的 - 但如果你有一些 C 代码,请发布它而不是伪代码。
  • 由于该问题缺乏数据结构和代码等基本内容,因此任何人都很难为您提供帮助。如果数据结构和我想象的一样,那么可以使用递归,但你必须一直向下到左边开始,然后在函数调用开始返回时检查“返回值”。跨度>
  • @Simons0n 你说得有道理,我只是想知道我是否可以使用如上所示的算法递归地解决这个问题

标签: c algorithm data-structures b-tree


【解决方案1】:

递归访问每个节点并将当前节点的 k 个最小元素添加到列表中。最后对其进行排序并获得第k个数字。

您也可以尝试比较 2 个列表并每次保留 k 个最小的列表,但我认为这会使代码看起来更复杂,最终会以大致相同或更差的速度结束,但肯定会占用更少的内存。

【讨论】:

    【解决方案2】:

    这个问题可以递归解决。你只需要让函数返回两件事:

    1. 第 k 个最小的键(或指向它的指针),如果它有 k 个或更多键。
    2. 树的大小(如果它的键少于 k 个)。

    通过在(根)节点的每个子树上调用函数,从最左边到最右边连续调用函数,并使用不同的(递减)参数 k:

    • 让原始/当前树为 R,通过调用 R 最左子树上的函数开始递归,其 k 与 R 接收到的相同。
    • 如果在 R 的子树上调用函数成功返回第 k 个最小的键,那么这就是答案并返回它。
    • 如果在 R 的某个子树 T 上调用函数找不到第 k 个最小的键,而是返回 T 的大小,例如 n (
    • 如果 T 是最右边的子树,则 R 的项目少于 k 个,返回 R 的大小(可以通过将其所有子树的大小和 R 的根中的键数相加来找到)。
    • 如果 n == k-1,则第 k 个最小的键是紧靠 T 右侧的键
    • 如果 n

    显然,您必须注意树的根不再有子树的终端条件。从概念上讲,通过允许包含 0 键的 NULL 子树可能更容易处理。

    【讨论】:

    • 在这种情况下,哪个应该是 branch[1] 的直接右子树?分支 [1] 还是分支 [0]?我正在测试您的解决方案,但我无法到达位于分支 [0] 的第三个最小元素。也许我错过了一些东西。如果我尝试在上面的代码中实施您的建议,您能否做出适当的更正?
    • @VassilisDe branch[1] 的直接右子树是 branch[2]。抱歉,我的术语似乎与您的不同。在我的算法中,branch[0] 是当前树的“根”,其中 { branch[1], branch[2], branch[3] } 是 branch[0] 拥有的 3 个子树。
    猜你喜欢
    • 2012-10-22
    • 2019-08-13
    • 1970-01-01
    • 2018-11-18
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 2022-01-04
    • 1970-01-01
    相关资源
    最近更新 更多