mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-08-10 17:12:18 +00:00
回到简体
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
## 5.2. 遞歸
|
||||
## 5.2. 递归
|
||||
|
||||
函數可以是遞歸的,這意味着函數可以直接或間接的調用自身。對許多問題而言,遞歸是一種強有力的技術,例如處理遞歸的數據結構。在4.4節,我們通過遍歷二叉樹來實現簡單的插入排序,在本章節,我們再次使用它來處理HTML文件。
|
||||
函数可以是递归的,这意味着函数可以直接或间接的调用自身。对许多问题而言,递归是一种强有力的技术,例如处理递归的数据结构。在4.4节,我们通过遍历二叉树来实现简单的插入排序,在本章节,我们再次使用它来处理HTML文件。
|
||||
|
||||
下文的示例代碼使用了非標準包 golang.org/x/net/html ,解析HTML。golang.org/x/... 目録下存儲了一些由Go糰隊設計、維護,對網絡編程、国際化文件處理、移動平台、圖像處理、加密解密、開發者工具提供支持的擴展包。未將這些擴展包加入到標準庫原因有二,一是部分包仍在開發中,二是對大多數Go語言的開發者而言,擴展包提供的功能很少被使用。
|
||||
下文的示例代码使用了非标准包 golang.org/x/net/html ,解析HTML。golang.org/x/... 目录下存储了一些由Go团队设计、维护,对网络编程、国际化文件处理、移动平台、图像处理、加密解密、开发者工具提供支持的扩展包。未将这些扩展包加入到标准库原因有二,一是部分包仍在开发中,二是对大多数Go语言的开发者而言,扩展包提供的功能很少被使用。
|
||||
|
||||
例子中調用golang.org/x/net/html的部分api如下所示。html.Parse函數讀入一組bytes.解析後,返迴html.node類型的HTML頁面樹狀結構根節點。HTML擁有很多類型的結點如text(文本),commnets(註釋)類型,在下面的例子中,我們 隻關註< name key='value' >形式的結點。
|
||||
例子中调用golang.org/x/net/html的部分api如下所示。html.Parse函数读入一组bytes.解析后,返回html.node类型的HTML页面树状结构根节点。HTML拥有很多类型的结点如text(文本),commnets(注释)类型,在下面的例子中,我们 只关注< name key='value' >形式的结点。
|
||||
|
||||
<u><i>golang.org/x/net/html</i></u>
|
||||
```Go
|
||||
@@ -35,7 +35,7 @@ type Attribute struct {
|
||||
func Parse(r io.Reader) (*Node, error)
|
||||
```
|
||||
|
||||
main函數解析HTML標準輸入,通過遞歸函數visit獲得links(鏈接),併打印出這些links:
|
||||
main函数解析HTML标准输入,通过递归函数visit获得links(链接),并打印出这些links:
|
||||
|
||||
<u></i>gopl.io/ch5/findlinks1</i></u>
|
||||
```Go
|
||||
@@ -61,7 +61,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
visit函數遍歷HTML的節點樹,從每一個anchor元素的href屬性獲得link,將這些links存入字符串數組中,併返迴這個字符串數組。
|
||||
visit函数遍历HTML的节点树,从每一个anchor元素的href属性获得link,将这些links存入字符串数组中,并返回这个字符串数组。
|
||||
|
||||
```Go
|
||||
// visit appends to links each link found in n and returns the result.
|
||||
@@ -80,9 +80,9 @@ func visit(links []string, n *html.Node) []string {
|
||||
}
|
||||
```
|
||||
|
||||
爲了遍歷結點n的所有後代結點,每次遇到n的孩子結點時,visit遞歸的調用自身。這些孩子結點存放在FirstChild鏈表中。
|
||||
为了遍历结点n的所有后代结点,每次遇到n的孩子结点时,visit递归的调用自身。这些孩子结点存放在FirstChild链表中。
|
||||
|
||||
讓我們以Go的主頁(golang.org)作爲目標,運行findlinks。我們以fetch(1.5章)的輸出作爲findlinks的輸入。下面的輸出做了簡化處理。
|
||||
让我们以Go的主页(golang.org)作为目标,运行findlinks。我们以fetch(1.5章)的输出作为findlinks的输入。下面的输出做了简化处理。
|
||||
|
||||
```
|
||||
$ go build gopl.io/ch1/fetch
|
||||
@@ -102,9 +102,9 @@ https://golang.org/dl/
|
||||
http://www.google.com/intl/en/policies/privacy/
|
||||
```
|
||||
|
||||
註意在頁面中出現的鏈接格式,在之後我們會介紹如何將這些鏈接,根據根路徑( https://golang.org )生成可以直接訪問的url。
|
||||
注意在页面中出现的链接格式,在之后我们会介绍如何将这些链接,根据根路径( https://golang.org )生成可以直接访问的url。
|
||||
|
||||
在函數outline中,我們通過遞歸的方式遍歷整個HTML結點樹,併輸出樹的結構。在outline內部,每遇到一個HTML元素標籤,就將其入棧,併輸出。
|
||||
在函数outline中,我们通过递归的方式遍历整个HTML结点树,并输出树的结构。在outline内部,每遇到一个HTML元素标签,就将其入栈,并输出。
|
||||
|
||||
<u><i>gopl.io/ch5/outline</i></u>
|
||||
```Go
|
||||
@@ -127,9 +127,9 @@ func outline(stack []string, n *html.Node) {
|
||||
}
|
||||
```
|
||||
|
||||
有一點值得註意:outline有入棧操作,但沒有相對應的出棧操作。當outline調用自身時,被調用者接收的是stack的拷貝。被調用者的入棧操作,脩改的是stack的拷貝,而不是調用者的stack,因對當函數返迴時,調用者的stack併未被脩改。
|
||||
有一点值得注意:outline有入栈操作,但没有相对应的出栈操作。当outline调用自身时,被调用者接收的是stack的拷贝。被调用者的入栈操作,修改的是stack的拷贝,而不是调用者的stack,因对当函数返回时,调用者的stack并未被修改。
|
||||
|
||||
下面是 https://golang.org 頁面的簡要結構:
|
||||
下面是 https://golang.org 页面的简要结构:
|
||||
|
||||
```
|
||||
$ go build gopl.io/ch5/outline
|
||||
@@ -149,14 +149,14 @@ $ ./fetch https://golang.org | ./outline
|
||||
...
|
||||
```
|
||||
|
||||
正如你在上面實驗中所見,大部分HTML頁面隻需幾層遞歸就能被處理,但仍然有些頁面需要深層次的遞歸。
|
||||
正如你在上面实验中所见,大部分HTML页面只需几层递归就能被处理,但仍然有些页面需要深层次的递归。
|
||||
|
||||
大部分編程語言使用固定大小的函數調用棧,常見的大小從64KB到2MB不等。固定大小棧會限製遞歸的深度,當你用遞歸處理大量數據時,需要避免棧溢出;除此之外,還會導致安全性問題。與相反,Go語言使用可變棧,棧的大小按需增加(初始時很小)。這使得我們使用遞歸時不必考慮溢出和安全問題。
|
||||
大部分编程语言使用固定大小的函数调用栈,常见的大小从64KB到2MB不等。固定大小栈会限制递归的深度,当你用递归处理大量数据时,需要避免栈溢出;除此之外,还会导致安全性问题。与相反,Go语言使用可变栈,栈的大小按需增加(初始时很小)。这使得我们使用递归时不必考虑溢出和安全问题。
|
||||
|
||||
**練習 5.1:** 脩改findlinks代碼中遍歷n.FirstChild鏈表的部分,將循環調用visit,改成遞歸調用。
|
||||
**练习 5.1:** 修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用。
|
||||
|
||||
**練習 5.2:** 編寫函數,記録在HTML樹中出現的同名元素的次數。
|
||||
**练习 5.2:** 编写函数,记录在HTML树中出现的同名元素的次数。
|
||||
|
||||
**練習 5.3:** 編寫函數輸出所有text結點的內容。註意不要訪問`<script>`和`<style>`元素,因爲這些元素對瀏覽者是不可見的。
|
||||
**练习 5.3:** 编写函数输出所有text结点的内容。注意不要访问`<script>`和`<style>`元素,因为这些元素对浏览者是不可见的。
|
||||
|
||||
**練習 5.4:** 擴展vist函數,使其能夠處理其他類型的結點,如images、scripts和style sheets。
|
||||
**练习 5.4:** 扩展vist函数,使其能够处理其他类型的结点,如images、scripts和style sheets。
|
||||
|
Reference in New Issue
Block a user