当前位置: 首页 > 面试题库 >

可以将结构指针方法中的指针重新分配给另一个实例吗?

汤兴生
2023-03-14
问题内容

我一直在研究Golang,并且已经实现了一些数据结构来学习该语言的工作方式。在为AVL树编写代码时遇到了以下问题:

从结构指针方法分配主指针似乎在函数范围之外无效。例如tree.rotateLeftToRoot()不会导致tree.left成为新树。

问题: 在Golang中,有没有一种方法可以在struct指针方法中重新分配指针,还是不建议这样做?在示例中,这将是"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()"可以避免此问题。这是可行的,但是当调用者确实只想能够调用一个函数来更新树时,混合效果并要求分配返回值似乎很肮脏。

可以从功能内将tree其设置为prevLeft吗?


问题答案:

指针是值,就像说int数字一样。区别在于该值的解释:指针被解释为内存地址,而ints被解释为整数。

当要改变类型的变量的值int,则通过一个指向int它的类型的*int,并且修改尖锐的物体:*i = newvalue(分配值是一个int)。

指针也是如此:当您想要更改指针类型的变量的值时*int,可以将指针传递给类型的指针,*int然后**int修改指向的对象:(*i = &newvalue分配的值为*int)。

需要传递指针,因为复制是根据传递的所有内容进行的,并且只能修改该副本。当你传递一个指针,同样的事情发生了:一个副本也取得了该指针的,但我们不修改该指针本身,而是
尖锐的 价值。

您要修改类型为的变量*AvlTree。在Go语言中,接收者不能是指向指针的指针。规范:方法声明:

接收者的类型必须是以下形式:(T或者*T使用括号),其中T类型名称是。用表示的类型T称为接收者 基本类型 ; 它不能是指针
或接口类型,并且必须在与方法相同的包中声明。

因此,您有2个选择:

  1. 要么编写一个简单的函数(而不是方法),该函数需要a **AvlTree,您就可以传递树指针的地址,因此该函数可以修改树指针(指向的对象)

  2. 或从函数/方法返回树指针,并让调用者将其分配给作为树指针的变量

解决您对返回树指针的担忧:这没有错。看一看内置函数append():它将函数附加到切片上

返回修改后的切片。您(调用方)必须将返回的切片分配给您的slice变量,因为append()如果其他元素不适合原始切片(并且由于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>


 类似资料:
  • 如果C中有指针(char*names[])和指向指针的指针(char**cur_name=names);有指向指针的指针吗? 或者指向指针的指针只是一个链表?也许这是个愚蠢的问题,但我想知道答案。

  • 我正在学习链表,以及如何在C中使用结构和指针创建链表。下面我举一个例子。据我所知,被调用的将头节点所在的结构的开始内存位置作为参数传递。push()函数的参数将结构节点作为指向指针的指针,因此它作为引用传递,而不是实际副本。因此,我们的的第一个指针只是指向头部节点的内存位置的指针,第二个指针指向该值,该值是头部节点指向的下一个内存位置。我们通过为结构节点分配一些内存,在结构节点内创建一个名为new

  • 我正在学习如何在C中使用并写了以下示例: 问:是否保证在所有情况下指向一个结构的指针都是指向它的第一个元素的完全相同的指针? 在这种特殊的情况下,它能像我预期的那样工作,但我不确定它是否能得到保证。编译器可以在开始时插入一些填充吗? 我唯一能找到的关于结构类型布局的是N1570的类型: 结构类型描述了一组按顺序分配的非空成员对象(在某些情况下,还包括一个不完整的数组),每个对象都有一个可选的指定名

  • 我试图理解在将值存储到结构或联合的成员中时,类型双关是如何工作的。 标准N1570指定 当值存储在结构或联合类型的对象(包括成员对象)中时,与任何填充字节相对应的对象表示的字节采用未指定的值。 所以我把它解释为如果我们有一个对象要存储到一个成员中,这样对象的大小等于,与填充相关的字节将具有未指定的值(即使我们定义了原始对象中的字节)。这是一个例子: 在我的机器。 打印的行为是否为这样的程序定义得很

  • 本文向大家介绍详解C++中的指针结构体数组以及指向结构体变量的指针,包括了详解C++中的指针结构体数组以及指向结构体变量的指针的使用技巧和注意事项,需要的朋友参考一下 C++结构体数组 一个结构体变量中可以存放一组数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组的不同之处在于:每个数组元素都是一个结

  • 问题内容: 根据这个问题的回答 关于指针与接收器的值的规则是,可以在指针和值上调用值方法,但是只能在指针上调用指针方法 但实际上我可以对非指针值执行指针方法: 那么,这是怎么了?这是新功能吗?还是对问题的回答是错误的? 问题答案: 您正在对指针值调用“指针方法”。在表达式中: 是类型(非指针);由于该方法具有指针接收者,并且由于接收者值是非指针且可寻址,因此它是以下各项的简写形式: 这是在规范中: