- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我一直在研究 Golang 并实现了一些数据结构以了解该语言的工作原理。我在为 AVL 树编写代码时遇到了以下问题:
从结构指针方法中分配主指针似乎在函数范围之外没有影响。例如。 tree.rotateLeftToRoot()
不会导致 tree.left
成为新树。
问题:有没有办法在 Golang 的结构指针方法中重新分配指针,或者通常不鼓励这样做?在示例中,这将是 "tree = prevLeft"
行。
代码片段:
//Graphical representation of t.rotateLeftToRoot():
// t L
// L R -> LL t
//LL LR LR R
func (tree *AvlTree) rotateLeftToRoot() {
if tree == nil {
return
}
prevLeft := tree.left
if prevLeft != nil {
tree.left = prevLeft.right //tree.left passed root its right branch
prevLeft.right = tree //tree becomes tree.left's right branch
tree.updateHeight()
prevLeft.updateHeight()
tree = prevLeft //desired behaviour: tree.left becomes the new tree
//actual behaviour: no effect when function returns
}
}
我试过设置树的值或地址的其他组合,但都没有达到预期的效果。例如,*tree = *prevLeft
导致无限循环。
附加说明:返回 tree
并设置 "tree = tree.rotateLeftToRoot()"
可避免此问题。这行得通,但是当调用者真的只是想调用一个函数来更新树时,混合效果并要求分配给返回值似乎很脏。
能否在函数内将树
设置为prevLeft
?
最佳答案
指针是值,就像我们说 int
数字一样。不同之处在于对该值的解释:指针被解释为内存地址,int
被解释为整数。
当你想改变int
类型变量的值时,你传递一个指向*int
类型的int
指针>,然后修改指向的对象:*i = newvalue
(分配的值是 int
)。
指针也是如此:当你想改变一个指针类型的变量的值时 *int
,你传递一个指向 *int
类型的指针**int
并修改指向的对象:*i = &newvalue
(分配的值是 *int
)。
传递指针是必需的,因为您传递的所有内容都会生成一个副本,您只能修改该副本。当您传递一个指针时,同样的事情会发生:该指针也有一个副本,但我们不是在修改指针本身,而是在修改指向的值。
您想修改类型为*AvlTree
的变量。在 Go 中,接收者不能是指向指针的指针。 Spec: Method declarations:
The receiver's type must be of the form
T
or*T
(possibly using parentheses) whereT
is a type name. The type denoted byT
is called the receiver base type; it must not be a pointer or interface type and it must be declared in the same package as the method.
所以你有两个选择:
要么写一个简单的函数(不是方法),它接受一个**AvlTree
,你可以传递你的树指针的地址,这样函数就可以修改树指针(指向对象)
或者从您的函数/方法返回树指针,并让调用者将其分配给作为树指针的变量。
解决您对返回树指针的担忧:这没有任何问题。看看内置函数 append()
: 它将元素附加到 slice 并 返回修改后的 slice 。您(调用者)必须将返回的 slice 分配给您的 slice 变量,因为如果附加元素不适合原始 slice ,append()
可能会通过分配一个新 slice 来修改 slice (并且由于 append()
接受一个非指针,必须返回修改后的值。
#1 的解决方案如下所示:
func rotateLeftToRoot(ptree **AvlTree) {
tree := *ptree
if tree == nil {
return
}
prevLeft := tree.left
if prevLeft != nil {
tree.left = prevLeft.right
prevLeft.right = tree
tree = prevLeft
}
*ptree = tree
}
我已经在 Go Playground 上实现了它证明它有效。
我用过这种类型:
type AvlTree struct {
value string
left *AvlTree
right *AvlTree
}
为了轻松检查结果,我实现了一些方法来生成 string
表示:
func (tree *AvlTree) String() string { return tree.str(1) }
func (tree *AvlTree) str(n int) string {
if tree == nil {
return "<nil>"
}
return fmt.Sprintf("%q\n%s%v,%v\n%s", tree.value, strings.Repeat("\t", n),
tree.left.str(n+1), tree.right.str(n+1), strings.Repeat("\t", n-1))
}
这就是树的构造和转换方式:
tree := &AvlTree{
value: "t",
left: &AvlTree{
value: "L",
left: &AvlTree{
value: "LL",
},
right: &AvlTree{
value: "LR",
},
},
right: &AvlTree{
value: "R",
},
}
fmt.Println(tree)
rotateLeftToRoot(&tree)
fmt.Println(tree)
原始树(没有变换):
"t"
"L"
"LL"
<nil>,<nil>
,"LR"
<nil>,<nil>
,"R"
<nil>,<nil>
以及转换后的树(正是您想要的):
"L"
"LL"
<nil>,<nil>
,"t"
"LR"
<nil>,<nil>
,"R"
<nil>,<nil>
关于pointers - 结构指针方法中的指针可以重新分配给另一个实例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35421495/
在指向指针的指针上使用指针算术是否定义明确? 例如 int a=some_value; int* p=&a; int**p2=&p; 现在对 p2 执行算术是否是定义明确的行为?(例如 p2+1、p2
我正在尝试使用一个函数来替代 C 中的 scanf()。该函数是由第三方编写的,并进行了相应的定义: ScanDecimal16uNumber - Scans a decimal 16bit unsi
我正在尝试为 Sundials CVODE 编写 CFFI 包装器图书馆。 SWIG 被 Sundial header 阻塞,因为它们相互关联,并且 SWIG 找不到合适的 header ,所以我手工
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: pass by reference not working 我正在阅读一些教程 linklistproblem在互联
我有一个代码片段很难理解。 char *c; // c is uni dimensional table ( single row ) char **p ; // p is a two dimen
我正在将一些代码移植到 Windows 并且被难住了。有一些代码在启动时自动运行以将指针复制到指针,并在退出时再次运行以删除指向指针的指针(如果它不为空)。 我已经创建了一个示例程序来重现该行为 in
将非 const 指针转换为 const 指针是合法的。 那为什么将指向非const的指针转换为指向const的指针是不合法的呢? 例如,为什么下面的代码是非法的: char *s1 = 0; con
将非 const 指针转换为 const 指针是合法的。 那为什么将指向非const的指针转换为指向const的指针是不合法的呢? 例如,为什么下面的代码是非法的: char *s1 = 0; con
将指向非常量的指针转换为指向常数的指针是合法的。 那么为什么将指向非const的指针转换为指向const的指针是不合法的呢? 例如,为什么下面的代码是非法的: char *s1 = 0; const
之间有什么区别 procedure(some_routine), pointer :: ptr ptr => null() 和 procedure(some_routine), pointer ::
只是为了消除一些困惑。我最近遇到了这段代码(使用指针到指针): int encode(unsigned char type, uint64_t input_length, unsigned char*
我已经阅读了我能找到的有关 C/C++ 指针的内容,但其中大部分是介绍性的,虽然它可以帮助您理解它们的使用,但在许多情况下,现有代码会抛出难以破译的示例。 我确实看到了一些例子,他们将一行代码分解成它
我一直在关注的学习数据结构的书使用“单指针”作为函数中的参数,这些函数在链表的不同位置添加新节点,例如在开始,在结束。同样在删除的情况下使用“pointer-to-pointer”。在所有这些情况下,
考虑这段代码: #define MAX 4 ............ ............ int** ptr = (int**)malloc(sizeof(int*)*MAX); *ptr =
如何将指向 void 对象的指针转换为类对象? 最佳答案 使用 static_cast。请注意,只有当指针确实指向指定类型的对象时,您才必须这样做;也就是说,指向 void 的指针的值取自指向此类对象
我假设一种语言的实现允许您将指针视为整数,包括对它们进行标准算术。如果由于硬件限制这是不现实的,请告诉我。如果编程语言通常没有这么强大的指针运算,但是在实践中是可行的,那么我仍然想知道这种实现BigI
我是一名 nodejs 开发人员,我通常为我的应用程序使用一个结构,该结构包含一个配置包/对象,该对象包含对我常用的库和配置选项的引用。通常,此配置对象也包含我的数据库连接,并且可以通过我的应用程序访
我已经在几个上下文中阅读过“胖指针”这个术语,但我不确定它的确切含义以及它何时在 Rust 中使用。指针似乎是普通指针的两倍,但我不明白为什么。它似乎也与特征对象有关。 最佳答案 术语“胖指针”用于指
这是让我困惑的代码。 static char *s[] = {"black", "white", "pink", "violet"}; char **ptr[] = {s+3, s+2, s+1, s
通用指针允许您创建指向指针的指针: void foo(Object **o) {} int main() { Object * o = new Object(); foo(&o); } s
我是一名优秀的程序员,十分优秀!