漫画算法-小灰的算法之旅(04)
1. 什么是数据存储的物理结构呢?
数组和链表都是在内存中实实在在存在的存储结构。逻辑结构是一个抽象的概念,它依赖于物理结构而存在。
线性结构 | 非线性结构 | |
---|---|---|
逻辑结构 | 顺序表、栈、队列 | 树、图 |
顺序存储结构 | 链式存储结构 | |
---|---|---|
物理结构 | 数组 | 链表 |
栈和队列,都属于逻辑结构,它们的物理实现既可以利用数组,也可以利用链表来完成。
2. 什么是栈
栈(stack):是一种线性数据结构,它就像一个放入乒乓球的圆筒容器,栈中的元素只能先入后出(First In Last Out)。最早进入的元素存放的位置叫做栈底(bottom),最后进入的元素存放的位置叫作栈顶(top)。
栈这种数据结构既可以用数组来实现,也可以用链表来实现。栈的基本操作是入栈和出栈。
入栈
入栈操作(push)就是把新元素放入栈中,只允许从栈顶一侧放入元素,新元素的位置将会成为新的栈顶(top).
出栈
出栈操作(pop) 就是把元素从栈中弹出,只有栈顶元素才允许出栈,出栈元素的前一个元素将会成为新的栈顶。
代码实现
用数组实现栈
// 不确定变量类型和结构,使用了interface
type Stack struct {
data []interface{}
}
func (s *Stack) Len() int {
return len(s.data)
}
func (s *Stack) Cap() int {
return cap(s.data)
}
func (s *Stack) IsEmpty() bool {
return len(s.data) == 0
}
// 入栈
func (s *Stack) Push(value interface{}) {
//将 新元素追加到栈顶
s.data = append(s.data, value)
}
func (s *Stack) Pop() (interface{}, error) {
theStack := s
if len(theStack.data) == 0 {
return nil, errors.New("Out of index ,len is 0")
}
//获取到栈顶元素
popValue := theStack.data[theStack.Len()-1]
//更换新到栈顶元素
theStack.data = theStack.data[:theStack.Len()-1]
s = theStack
return popValue, nil
}
//获取栈顶元素
func (s *Stack) Top() (interface{}, error) {
if s.IsEmpty() {
return nil, errors.New("Out of index, len is 0")
}
return s.data[len(s.data)-1], nil
}
func main(){
var myStack Stack
myStack.Push(1)
myStack.Push("test")
log.Println("stack len is :",myStack.Len())
pop, _ := myStack.Pop()
log.Println("stack pop value is :",pop)
log.Println(" pop stack after len is :",myStack.Len())
}
使用单链表实现栈
type LinklistStack struct {
headNode *Node
}
type Node struct {
data interface{}
next *Node
}
func (l LinklistStack) IsEmpty() bool {
return l.headNode==nil
}
//初始化一个栈
func New() *LinklistStack {
return &LinklistStack{nil}
}
// 链表的头插法 入栈
func (l *LinklistStack) push(value interface{}) {
newNode :=&Node{
data: value,
}
newNode.next=l.headNode
l.headNode=newNode
}
func (l *LinklistStack)pop() (interface{},error) {
if l.IsEmpty() {
return nil,errors.New("栈以空")
}
popValue :=l.headNode.data
l.headNode=l.headNode.next
return popValue,nil
}
func (l *LinklistStack) Traverse() {
if l.IsEmpty() {
log.Println("栈已空")
return
}
currentNode :=l.headNode
for currentNode!=nil {
log.Printf("%v\t",currentNode.data)
currentNode=currentNode.next
}
}
func main(){
log.Println(" linklistStack ")
stack := New()
stack.push(123)
stack.push("test")
stack.push("hello")
stack.Traverse()
value, _ := stack.pop()
log.Println("stack.pop() value is ",value)
stack.Traverse()
}
时间复杂度
入栈和出栈只会影响到最后一个元素,不涉及其他元素的整体移动,所以无论是以数组还是以链表实现,入栈和出栈的时间复杂度都为O(1)。