【声明】
非完全原创,部分内容来自于学习其他人的理论和B站视频。如果有侵权,请联系我,可以立即删除掉。
一、概念
1、线性表
线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(循环链表的首位相连,因此不符合该定义,但它也是线性表的一种)。
线性表是一种逻辑上的结构, 主要强调数据之间的关系,不关心底层如何实现。因此线性表可以用指针的方式,也可以用数组的方式来实现
- 数组、链表、栈、队列是四种最常见的线性表
1.1、顺序表
顺序表是在计算机内存中以数组的形式保存的线性表,即, 采用顺序存储结构的线性表通常称为顺序表。
线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。
//定义一个长度为1024的顺序表
const maxLen = 1024
type sequence_list struct {
data [maxLen]int
size int
}
1.2、单链表
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素 + 指针。元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
优缺点:
- 优点:单向链表增加删除节点简单。遍历时候不会死循环
- 缺点:只能从头到尾遍历。只能找到后继,无法找到前驱
1.3、双链表
与单链表不一样的是,双链表中每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
优缺点:
- 优点:可以找到前驱和后继,因此遍历链表时可从后往前,也可以从前往后
- 缺点:比单链表多一个指针存储空间。
二、单链表的实现
本文中用链式结构是实现了单链表,数组的实现方式参考:https://www.cnblogs.com/pureayu/p/13614443.html
1、特点
由各个内存结构通过一个指向下一个结点的指针链接在一起组成,每一个内存结构都存在后继内存结构(链尾除外),内存结构由数据域和指针域组成。
2、说明
(1)为了方便,单链表带有一个不存放任何数据的头节点。主要是为了在操作链表时,不用单独区分链表头指针是否为空,方便代码的书写
(2)主要的方法有:
方法 | 说明 |
---|---|
IsEmpty() bool |
判断单链表是否为空 |
Size() |
获取链表的长度 |
CreateList() *BookName |
创建一个单链表 |
GetValueInfo() string |
获取当前结点数据域的字符串 |
AddFirst(newNode *BookName) |
链表头部插入元素 |
AddLast(newNode *BookName) |
链表尾部插入元素 |
RemoveFirst() *BookName |
删除链表头部元素,并返回已删除的元素 |
RemoveLast() *BookName |
删除链表尾部元素,并返回已删除的元素 |
GetFirst() *BookName |
获取链表头部元素 |
GetLast() *BookName |
获取链表尾部元素 |
Contains(node *BookName) bool |
判断链表中是否存在某结点 |
List() |
打印单链表中的所有元素及指向关系 |
Reverse() |
将链表进行反转 |
3、代码
package sll
import "fmt"
type BookName struct {
Rank int
Name string
Next *BookName
}
//单链表的头结点值设为空, 指针设为nil
func CreateList() *BookName {
return &BookName{
}
}
func (head *BookName) GetValueInfo() string {
return strconv.Itoa(head.Rank) + " " + head.Name
}
func (head *BookName) IsEmpty() bool {
return head.Next == nil
}
func (head *BookName) Size() int {
cnt := 0
for tmp := head; tmp.Next != nil; tmp = tmp.Next {
cnt++
}
return cnt
}
//尾部插入元素
func (head *BookName) AddLast(newNode *BookName) {
var tmp *BookName
for tmp = head; tmp.Next != nil; tmp = tmp.Next {
}
tmp.Next = newNode
}
//头部插入元素
func (head *BookName) AddFirst(newNode *BookName) {
var tmp *BookName = newNode
tmp.Next =