雙鏈表算法

  • 雙鏈表最大的優勢就是可以雙向遍歷
package main

import "fmt"

type Node struct {
	num  int
	name string
	pre  *Node
	next *Node
}

// 末尾插入
func insert(head *Node, newNode *Node) {
	tmp := head
	for {
		//  插入末尾,先連接左邊,後連接右邊
		if tmp.next == nil {
			tmp.next = newNode
			newNode.pre = tmp
			break
		}
		tmp = tmp.next
	}
}

// 正向遍歷
func list(head *Node) {
	tmp := head
	if tmp.next == nil {
		fmt.Printf("link is null")
	}

	for {
		if tmp.next != nil {
			// 第一個tmp代表head的下一個
			fmt.Printf("[%d] = %s \n", tmp.next.num, tmp.next.name)
		} else {
			break
		}
		tmp = tmp.next
	}
}

// 反向遍歷
func reverselist(head *Node) {
	tmp := head
	if tmp.next == nil {
		fmt.Printf("link is null")
	}
	// 先將tmp指向鏈表末尾
	for {
		if tmp.next == nil {
			break
		}
		tmp = tmp.next
	}

	for {
		// 注意頭節點並不是空的,裏面還有mext和pre
		if tmp.pre != nil {
			fmt.Printf("[%d] = %s \n", tmp.num, tmp.name)
		} else {
			break
		}
		tmp = tmp.pre
	}
}

func main() {
	// head是隨機位置的指針
	head := &Node{}

	// 插入數據不需傳遞下一個node地址
	node := &Node{
		num:  1,
		name: "amber",
	}
	node2 := &Node{
		num:  2,
		name: "alice",
	}
	node3 := &Node{
		num:  3,
		name: "necy",
	}
	node4 := &Node{
		num:  4,
		name: "bella",
	}

	insert(head, node)
	insert(head, node2)
	insert(head, node3)
	insert(head, node4)

	list(head)
	fmt.Println()
	reverselist(head)

}

輸出結果:
在這裏插入圖片描述

  • 雙鏈表有序插入和刪除
package main

import "fmt"

type Node struct {
	num  int
	name string
	pre  *Node
	next *Node
}

func orderInsert(head *Node, newNode *Node) {
	tmp := head
	for {
		// 必須放在前面,防止在末尾nil,被插在最後
		if newNode.num == tmp.num {
			fmt.Printf("node has already in link\n")
			break
		}
		// 放在第二順位,當未找到插入最後
		if tmp.next == nil {
			tmp.next = newNode
			newNode.pre = tmp
			break
		}
		// 遍歷是從前往後,判斷條件tmp.next是保證在tmp後面插入前插入
		if newNode.num < tmp.next.num {
			// 先關聯右邊,再關聯左邊
			newNode.next = tmp.next
			newNode.pre = tmp

			tmp.next.pre = newNode
			tmp.next = newNode
			break
		}

		tmp = tmp.next
	}

}

func list(head *Node) {
	tmp := head
	if tmp.next == nil {
		fmt.Printf("link is null")
	}

	for {
		if tmp.next != nil {
			// 第一個tmp代表head的下一個
			fmt.Printf("[%d] = %s \n", tmp.next.num, tmp.next.name)
		} else {
			break
		}
		tmp = tmp.next
	}
}

func delete(head *Node, num int) {
	tmp := head
	for {
		if tmp == nil {
			fmt.Printf("link is null")
			break
		}
		// 注意這裏要找到tmp.next,因爲找到tmp是要刪除節點無法刪除
		if tmp.num == num {
			if tmp.next == nil {
				tmp.pre.next = nil
				break
			} else {
				tmp.next.pre = tmp.pre
				tmp.pre.next = tmp.next
				break
			}
		}
		tmp = tmp.next

	}
}

func main() {
	// head是隨機位置的指針
	head := &Node{}

	// 插入數據不需傳遞下一個node地址
	node := &Node{
		num:  1,
		name: "amber",
	}
	node2 := &Node{
		num:  2,
		name: "alice",
	}
	node3 := &Node{
		num:  3,
		name: "necy",
	}
	node4 := &Node{
		num:  3,
		name: "zoe",
	}

	orderInsert(head, node4)
	orderInsert(head, node2)
	orderInsert(head, node)
	orderInsert(head, node3)
	list(head)

	fmt.Printf("****************\n")

	delete(head, 2)
	list(head)

}


輸出結果:
在這裏插入圖片描述
PS:這裏演示的是重複插入在最後的情況,所以要將重複判斷放在末尾插入之前

總結:
1、無論單鏈表還是雙鏈表插入一定定位在tmp和tmp.next之間
2、頭節點數據是空的,但不代表頭節點=nil
3、刪除和插入是一定要考慮刪除的恰好是最後的節點或者插入到最後的情況

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章