一,前言
程序运行的基础就是数据结构和算法。数据结构非常的重要,既然是基础就得好好学习。
二,线性表
零个或多个数据元素的有限序列
1,数组
//数组
package main
import "fmt"
func main() {
arry := []int{1, 5, 4, 8, 7, 6, 3, 11}
fmt.Println(arry[2])
fmt.Println(findVal(arry,3))
}
//查询数组中是否存在要查找的值,返回数组下标,如果没有返回-1
func findVal(arry []int, a int) int{
for i,a:=range arry{
if a==3{
return i
}
}
return -1
}
//找到相同元素的位置并插入
func insertVal(arry []int, a int) bool {
var res []int
index := findVal(arry, a)
if index > 0 {
fmt.Println(arry[:index])
res = append(res, arry[:index]...)
res = append(res, a)
res = append(res, arry[index:]...)
fmt.Println(res)
return true
}
return false
}
查询速度快,但是插入和删除会移动大量的元素。
2,链表
//节点
type Node struct {
Data interface{}
Next *Node
}
//单链表
type List struct {
headNode *Node
}
链表也是线性表,插入和删除不需要移动大量元素了。
1,头插法
//头插法
func (l *List) Add(data Object) *Node {
node := &Node{Data: data}
node.Next = l.headNode
l.headNode = node
return node
}
jdk1.7之前,HashMap 是数组链表来实现的,链表采用的是头插法,方便插入元素。但是HashMap不是线程安全的,多线程中如果数组扩容会出现环链的现象。1.8之后采用尾插法,尾插法避免了环链,但是插入的效率明显降低了。
2,尾插法
//尾插法
func (l *List) Append(data interface{}) {
node := &Node{Data: data}
if l.IsEmpty() {
l.headNode = node
}
cur := l.headNode
for cur.Next != nil {
cur = cur.Next
}
cur.Data = node
}
尾插法需要遍历到尾部,才能插入元素,但是因为链表复制的时候不会出现,新的链表元素顺序和原来的链表是一样的。不会出现环链了。多线程的情况下,如果扩容,线程挂起,也就是在执行一遍链表的复制而已。避免了环链的产生。
突然感觉刚才创建的结构不合适,因为尾插法会比较慢。
//修改之后的单链表
type List struct {
headNode *Node
lastNode *Node
length int
count int
}
这样就可以直接找到尾部
//头插法
func (l *List) Add(data interface{}) *Node {
node := &Node{Data: data}
if l.IsEmpty() {
l.headNode = node
l.lastNode = node
} else {
node.Next = l.headNode
l.headNode = node
}
l.length++
return node
}
//尾插法
func (l *List) Append(data interface{}) {
node := &Node{Data: data}
if l.IsEmpty() {
l.headNode = node
l.lastNode = node
} else {
l.lastNode.Next = node
l.lastNode = node
}
l.length++
}
3,链表排序
func Test_Order(t *testing.T) {
l := &List{}
for i := 0; i < 10; i++ {
l.Add(i)
}
l.orderList()
fmt.Println("排序后:",l.count)
cur := l.headNode
for {
fmt.Println(cur.Data)
cur = cur.Next
if cur == nil {
break
}
}
}
func (l *List) orderList() {
cur := l.headNode
for {
cur = l.Change(cur)
fmt.Println(cur.Data)
if cur.Next == nil {
break
}
}
}
func (l *List) Change(cur *Node) *Node {
if cur.Next == nil {
return nil
}
second := cur.Next
l.count++
if cur.Data.(int) > second.Data.(int) {
tmp := cur.Data
cur.Data = second.Data
second.Data = tmp
return l.headNode
} else {
return second
}
}
统计了下执行次数:174次
三,总结
数组的修改会比较的麻烦,因为大量的元素需要整体移动。链表在插入,修改方面进行了优化。
链表在读取方面和数组虽然有差异但是效率差不多。