前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >amt 数组算法

amt 数组算法

作者头像
魂祭心
发布2020-07-06 22:44:11
4640
发布2020-07-06 22:44:11
举报
文章被收录于专栏:魂祭心魂祭心

Amt

代码语言:javascript
复制
type Node struct {
	Bmap   []byte               //是否设置值 仅第一个字节游泳。八位代表八个自节点是否存在
	Links  []cid.Cid            //自节点
	Values []*cbg.Deferred     //Flush 将 expVals设置到Values上面

	expLinks []cid.Cid         //设置的子节点值
	expVals  []*cbg.Deferred   //设置的值
	cache    []*Node           //子节点缓存
}

基本结构

amt数据结构是一个八叉树,所有的数据节点都存储在叶子节点上。数组形态就表现在叶子上,把整个叶子节点按顺序拼在一起就是amt数组。不存在数据的索引节点会裁减掉,节省所需的数据空间。

设置数据

通过id确定叶子节点位置

  1. 如果该叶子节点所在的索引节点有数据,那么直接设置这个数据即可。
  1. 如果叶子节点位于当前树容量之内,但是原来不存在该路径数据,需要新建这个索引路径再把数据挂上去。
  1. 如果设置的数据位置超过当前八叉树容量,那么先要扩充当前八叉树深度,原数据作为新树的左子树。新节点新建一条路径挂上写入的叶子节点
代码语言:javascript
复制
    //增长层数
	for i >= nodesForHeight(width, int(r.Height)+1) {
		if !r.Node.empty() {
			if err := r.Node.Flush(ctx, r.store, int(r.Height)); err != nil {
				return err
			}

			c, err := r.store.Put(ctx, &r.Node)
			if err != nil {
				return err
			}

			r.Node = Node{
				Bmap:  []byte{0x01},
				Links: []cid.Cid{c},
			}
		}
		r.Height++
	}
    //设置值
	addVal, err := r.Node.set(ctx, r.store, int(r.Height), i, &cbg.Deferred{Raw: b})
	if err != nil {
		return err
	}

	if addVal {
		r.Count++
	}

查找数据

添加数据时候,首先通过高度确定最后一层的数量,在通过数组索引需要确定第一层的索引节点,然后递归,通过倒数第二层的数据宽度确定第二层的索引节点,这样层层找到叶子节点数据

代码语言:javascript
复制
func (n *Node) get(ctx context.Context, bs cbor.IpldStore, height int, i uint64, out interface{}) error {
	subi := i / nodesForHeight(width, height)
	set, _ := n.getBit(subi)
	if !set {
		return &ErrNotFound{i}
	}
	if height == 0 {
        //找到自节点
		n.expandValues()

		d := n.expVals[i]

		if um, ok := out.(cbg.CBORUnmarshaler); ok {
			return um.UnmarshalCBOR(bytes.NewReader(d.Raw))
		} else {
			return cbor.DecodeInto(d.Raw, out)
		}
	}

	subn, err := n.loadNode(ctx, bs, subi, false)
	if err != nil {
		return err
	}

	return subn.get(ctx, bs, height-1, i%nodesForHeight(width, height), out)  //递归向下找自节点
}

删除数据

  1. 删除数据先查找到数据位置和路径
  2. 如果该数据所在的索引节点上还存在其他数据,直接清除数据,设置标识即可。
  1. 删除数据之后层层检查索引节点,如果索引节点下面是空的,那么就删除这个空节点。这样可以收缩树的大小防止浪费空间。
  1. 如果清除子树后,发现跟节点只存在一个自节点那么可以收缩整棵树的大小,减少高度,进一步减少存储数据的量以及索引的节点数目
代码语言:javascript
复制
func (n *Node) delete(ctx context.Context, bs cbor.IpldStore, height int, i uint64) error {
	subi := i / nodesForHeight(width, height)
	set, _ := n.getBit(subi)
	if !set {
		return &ErrNotFound{i}
	}
	if height == 0 {
        //找到节点,清理该节点
		n.expandValues()

		n.expVals[i] = nil
		n.clearBit(i)

		return nil
	}

	subn, err := n.loadNode(ctx, bs, subi, false)
	if err != nil {
		return err
	}

    //递归向下查找
	if err := subn.delete(ctx, bs, height-1, i%nodesForHeight(width, height)); err != nil {
		return err
	}

	if subn.empty() {
        //清理空枝
		n.clearBit(subi)
		n.cache[subi] = nil
		n.expLinks[subi] = cid.Undef
	}

	return nil
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Amt
    • 基本结构
      • 设置数据
      • 查找数据
      • 删除数据
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档