数据结构和算法--线性表


数据结构:
串-字符串

线性表
经典排序算法 上篇
经典排序算法 下篇


一,前言

程序运行的基础就是数据结构和算法。数据结构非常的重要,既然是基础就得好好学习。

二,线性表

零个或多个数据元素的有限序列

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次

三,总结

数组的修改会比较的麻烦,因为大量的元素需要整体移动。链表在插入,修改方面进行了优化。

链表在读取方面和数组虽然有差异但是效率差不多。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值