数据结构 の 链表和串
一.链表
1.1双向链表的基本操作
package main
import "fmt"
type Node struct {
Data int
PrePoint *Node
NextPont *Node
}
type LinkList struct {
head *Node
current *Node
tail *Node
}
func main() {
datas := []int{1, 21, 31, 51, 62, 2, 3, 42, 33, 12, 12}
linklists := new(LinkList)
for _, v := range datas {
node := new(Node)
node.Data = v
InsertLinkList(node, linklists)
}
node := linklists.head
ShowLinkList(node)
}
func InsertLinkList(node *Node, link *LinkList) {
if link.head == nil {
link.head = node
link.current = node
link.tail = node
} else {
link.tail.NextPont = node
node.PrePoint = link.tail
link.tail = node // 只移动尾,头指针一直不动,中间的指针也一直不动
}
}
func ShowLinkList(node *Node) {
for node != nil {
fmt.Println(node.Data)
node = node.NextPont
}
}
1.2 将两个递增的链表合成一个
队
循环队
让队尾指针rear
指向刚进队的元素位置,队首指针front
指向刚出队的元素位置,进队的时候rear
向后移动,出队的时候,front
向后移动。
对为空的条件
front==rear
队满的条件
(rear+1)%max==front
队列的存值和取值
// 如果队不满,先移动指针,再存值
if (rear+1)%max != front {
rear = (rear + 1) % max
r := q[rear]
}
// 如果队列不为空,先移动指针,再取值
if rear != front {
front = (front + 1) % max
r:=q[front]
}
二.串
简单的模式匹配算法
时间复杂度 O(mn)
package main
import "fmt"
func Index(a, a1 string) int {
i, j, k := 0, 0, 0
s := []byte(a)
p := []byte(a1)
for i < len(s) && j < len(p) {
if s[i] == p[j] {
i++
j++
} else {
j = 0 // 如果没有找到的话,i接着走,k+1
k++
i = k // 匹配不上的话,才会走下边这条路,所以k能记录一开始匹配的位置
}
}
if j >= len(p) {
return k
} else {
return 0
}
}
func main() {
index := Index("absegabciegeggegeabcacbab", "ciegegge")
fmt.Println(index)
}
KMP
查考文献https://www.zhihu.com/question/21923021
package main
import "fmt"
func KMP(t1, p1 string) int {
str := []byte(t1)
p := []byte(p1)
next := getNext(p)
i, j := 0, 0
for i < len(str) && j < len(p) {
if j == -1 || str[i] == p[j] { //j=-1 是因为next的数组的第一个是-1
i++
j++
} else {
// 只要匹配了,i和 j 就一起往前走,如果不匹配,那么就让 j 回朔到 next[j] 的位置
j = next[j]
}
}
if j == len(p) {
return i - j
} else {
return -1
}
}
func getNext(str []byte) []int {
next := make([]int, len(str)+1)
next[0] = -1 //第一是个特殊情况
// 看一下那个图,上边的模板字符串和下边的模板字符串是错开的,上边的1,对应下边的0,所以上边的0,应该对应下边的-1
// j=-1是为了好算,不然模板字符串自己和自己匹配,第一个是个特殊情况。
i, j := 0, -1
// 过程和 KMP一样,都是i不同,只有下面的模板字符串的j在来回的跑
for i < len(str) {
if j == -1 || str[i] == str[j] {
i++
j++
next[i] = j
} else {
// 根据已经建好的next数组回朔
// 和上面kmp一样
j = next[j]
}
}
return next
}
func main() {
a := "ababaeabacaaaaaddfdfdfdfdf"
b := "aca"
rel := KMP(a, b)
fmt.Println(rel)
}
// 输出8
散列表
常见的 Hash 构造方法
- 直接地址法
- 除留余数法
解决 hash 冲突的方法
- 线性探索法: 容易产生堆积问题
- 平方探索法:平方探索法可以减少堆积问题,比如运算出来的hash值为
d
,那么 d+12,d-12,d+22 ,d-22,d+32,d-32 但是问题是不能探索到 hash表上的所有单元。 - 链地址方法,把所有的地址用单链表串起来。