Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

迭代器设计 #255

Closed
wants to merge 7 commits into from
Closed

迭代器设计 #255

wants to merge 7 commits into from

Conversation

dxyinme
Copy link
Contributor

@dxyinme dxyinme commented May 2, 2024

目前实现了Iterator接口以及接口在RBTree中所需要的新方法和使用方式,其他容器的接口实现方法也按照这样设计

@dxyinme dxyinme mentioned this pull request May 2, 2024
internal/iterator/iterator.go Show resolved Hide resolved
@@ -79,6 +104,15 @@ func newRBNode[K any, V any](key K, value V) *rbNode[K, V] {
}
}

// 获取起始点的迭代器
func (rb *RBTree[K, V]) Begin() iterator.Iterator[pair.Pair[K, V]] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

在类似树形结构里面,可以实现多种迭代器,分别按照不同的迭代顺序。比如说中序遍历,先序遍历等等……不同方法返回不同的迭代器。

internal/tree/red_black_tree.go Outdated Show resolved Hide resolved
@flycash
Copy link
Contributor

flycash commented May 7, 2024

我不太能接受这种设计。我认为 RBTree 不应该定义 DeleteIt 和 FindIt 这一类的方法。当我操作 Iterator 的时候,我希望我操作的就是 Iterator,而不是我还需要把这个东西传递回去 RBTree。

@dxyinme
Copy link
Contributor Author

dxyinme commented May 7, 2024

我不太能接受这种设计。我认为 RBTree 不应该定义 DeleteIt 和 FindIt 这一类的方法。当我操作 Iterator 的时候,我希望我操作的就是 Iterator,而不是我还需要把这个东西传递回去 RBTree。

那我按照你的建议再改改

@dxyinme
Copy link
Contributor Author

dxyinme commented May 9, 2024

我不太能接受这种设计。我认为 RBTree 不应该定义 DeleteIt 和 FindIt 这一类的方法。当我操作 Iterator 的时候,我希望我操作的就是 Iterator,而不是我还需要把这个东西传递回去 RBTree。

已经按照你的建议修改。

Copy link
Contributor

@flycash flycash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注意一点 Go 的注释规范,必须以方法名或者类型名作为开头。例如:

// Iterator xxxxx
type Iterator[T any] interface {
}

@@ -95,6 +134,14 @@ func (rb *RBTree[K, V]) Delete(key K) (V, bool) {
return v, false
}

// 查找结点 (但是返回iterator)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个方法不需要。因为正常在使用 Iterator 的时候,查找是这么用的:

for itr.Next() {
    val := itr.Get()
    if val == xxx {
     // 这就是判定
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样的话 iterator无法支持查找欸,比如我想使用iterator实现一个功能就是查找到比 key 大 和 比 key 小的 10 个值,本来可以做到O(logN)的现在只能做到O(N)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iterator 本身的语义就是迭代。Find 类的方法可以在 RBTree 上实现,但是没有必要在 Iterator 这里。

internal/iterator/iterator.go Show resolved Hide resolved
}

func (iter *rbTreeIterator[K, V]) Next() bool {
fmt.Println(iter.currNode.key, iter.currNode.value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这种 DEBUG 信息要记得删了

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的


func (iter *rbTreeIterator[K, V]) Next() bool {
fmt.Println(iter.currNode.key, iter.currNode.value)
iter.err = nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个 err 暂时不要置为 nil,如果要是已经不为 nil 了,你就永远返回 false。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

或者说,我们认为,如果 err 不为 nil,那么就说明这个 iterator 不可用了。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK 可以的

@@ -53,6 +59,26 @@ type rbNode[K any, V any] struct {
left, right, parent *rbNode[K, V]
}

func (node *rbNode[K, V]) getNext() *rbNode[K, V] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要定义在这里。你想,如果我们是广度优先遍历,那么 next 的概念是完全不一样的。你应该把这个挪过去 Iterator 的实现里面。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我没理解错的话,这是一个中序遍历的吧?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

确实是一个中序遍历,但是我有一个疑问就是对于一个红黑树来说,我们需要广度优先遍历吗,或者说我们需要除了中序遍历 (Begin 从小到大) 和反向中序遍历 (RBegin 从大到小)以外的遍历方式么

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你不需要纠结要不要,只是说我们需要留出来这个扩展点。所以你现在并不能直接说我这里不可能用别的遍历方式。而且你从设计理念上来说,next 就是归属你 iterator 的概念,一个红黑树是没有这个概念的。

return vis > 0
}

type rbTreeIterator[K any, V any] struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

改个名字,名字里面包含它是如何遍历的,我的理解是你这个是中序遍历的?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

后续万一要实现广度优先、前序、后序,名字就能够区分出来。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

把这个 iterator 挪出去作为一个单独的文件,测试也要相应的挪出去。

iter.nxtNode = iter.currNode.getNext()
return true
}
iter.err = ErrRBTreeIteratorNoNext
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NoNext 算是正常结束,你这里不用标记一个错误。

}

func (iter *rbTreeIterator[K, V]) Get() (kvPair pair.Pair[K, V]) {
iter.err = nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同样不能设置为 nil

return curr
}

func (rb *RBTree[K, V]) Begin() iterator.Iterator[pair.Pair[K, V]] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同样将 Begin 改个名字,指明你的遍历顺序,在注释里面也解释一下。

// 获取迭代器当前所指向的节点的信息
Get() T

// 获取error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

获取 error。当你在执行 Get 或者 Delete 之后,如果有必要,可以通过该方法来检测是否运作正常。

@flycash flycash closed this May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants