数据结构 の 链表和串

一.链表

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 构造方法

  1. 直接地址法
  2. 除留余数法

解决 hash 冲突的方法

  1. 线性探索法: 容易产生堆积问题
  2. 平方探索法:平方探索法可以减少堆积问题,比如运算出来的hash值为d,那么 d+12,d-12,d+22 ,d-22,d+32,d-32 但是问题是不能探索到 hash表上的所有单元。
  3. 链地址方法,把所有的地址用单链表串起来。
posted @ 2021-07-16 17:11  沧海一声笑rush  阅读(104)  评论(0编辑  收藏  举报