线性表
动态数组(切片)、链表、栈、队列都属于线性结构。
线性表是零个或者多个数据元素的有限序列,数据元素之间是有顺序的,数据元素个数是有限的,数据元素的类型是相同的。
头节点只有一个后继节点,尾节点只有一个前继节点,中间节点既有前继节点又有后续节点。
线性表的抽象数据类型定义
ADT线性表(List)
Data
线性表的数据对象集合为{ a1, a2, ……, an },每个元素的类型均为DataType。其中,除第一个元素a1外,每个元素有且只有一个直接前驱元素,除了最后一个元素an外,每个元素有且只有一个直接后继元素。数据元素之间的关系是一一对应的。
Operation(操作)
// 初始化,建立一个空的线性表L。
InitList(*L);
// 若线性表为空,返回true,否则返回false
ListEmpty(L);
// 将线性表清空
ClearList(*L);
// 将线性表L中的第i个位置的元素返回给e
GetElem(L, i, *e);
// 在线性表L中的第i个位置插入新元素e
ListInsert(*L, i, e);
// 删除线性表L中的第i个位置元素,并用e返回其值
ListDelete(*L, i, *e);
// 返回线性表L的元素个数
ListLength(L);
// 销毁线性表
DestroyList(*L);
链表
概念
数据结构中叫结点
数据域
指针域
结点分类
头结点:数据域为空,地址域指向第一个数据结点。没有前驱,只有后继。完整链表有头结点,实际视情况可以没有
数据结点:既有前驱又有后继。
尾结点:也是数据结点。指针域为空。只有前驱,没有后继。
链表的构成
type LinkNode struct {
Data interface{}
Next *LinkNode
}
链表的操作方法
1.创建链表
2.打印链表
3.获取链表长度(数据结点的个数,不包含头结点)
4.插入结点:头插法、尾插法,按位置插入
5.按位置插入
6.按数据删除
7.按数据查找
8.销毁链表
go实现链表
创建链表
func (node *LinkNode) Create(Data ...interface{}) {
if node == nil || Data == nil {
return
}
if len(Data) == 0 {
return
}
// 循环遍历Data依次取出创建单向链表
for _, v := range Data {
//创建新结点,并且初始化
newNode := new(LinkNode)
newNode.Data = v
newNode.Next = nil
//新结点加入链表
node.Next = newNode
//更新新结点为当前结点
node = node.Next
}
}
主函数
func main() {
node := new(LinkNode)
node.Create(1,2,3,4,5)
}
打印链表
//递归打印
func (node *LinkNode) Print1() {
if node == nil {
return
}
if node.Data != nil {
fmt.Print(node.Data, " ")
}
node.next.Print1()
}
//循环打印
func (node *LinkNode) Print2() {
if node == nil {
return
}
for node.Next != nil {
node = node.Next //跳过头结点
fmt.Print(node.Data, " ") //打印
}
}
获取链表的长度
func (node *LinkNode) Length() int {
if node == nil {
return -1
}
for node.Next != nil {
node = node.Next
i++
}
return i
}
头插法
func (node *LinkNode) InsertByHead(Data interface{}) {
if node == nil {
return
}
//创建新结点,初始化
newNode := new(LinkNode)
newNode.Data = Data
newNode.next = node.next //新结点指向第一个数据结点
//头结点下一个节点赋值为新结点
node.Next = newNode
}
尾插法
func (node *LinkNode) InsertByTail(Data interface{}) {
if node == nil {
return
}
//遍历
for node.next != nil {
node = node.next
}
//创建新结点,初始化
newNode := new(LinkNode)
newNode.Data = Data
newNode.next = nil
node.next = newNode
}
按照位置插入结点
func (node *LinkNode) InsertByIndex(Data interface{}, index int) {
//容错处理
if node == nil {
return
}
if index < 0 || index > node.Length() {
return
}
//定义前一个节点
preNode := node
//找寻插入位置
for i:= 0; i < index; i++ {
//prenode指向当前结点,然后node变更为下一个结点
preNode = node
node = node.Next
}
//创建新结点
newNode := new(LinkNode)
newNode.Data = Data
newNode.next = nil
preNode.next = newNode
newNode.next = node
}
比较顺序表和链式表
顺序表:内存连续,查找快,内存占用小
缺点:增,删效率低
场景:数据批量查询
链式表:散乱存储,增删效率高,
缺点:查询效率低,需要额外占用内存
场景:增删频繁