数据结构学习:栈与队列

本篇文章主要内容:

  • 栈与队列的基本概念
  • 栈与队列的基本结构
  • 栈与队列的互相实现

概念

  • 栈(stack)是限定仅在表尾进行插入和删除操作的线性表。

  • 我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(LastIn First Out)的线性表,简称LIFO结构。

结构

对栈来说,一般我们只需要关注:push, pop, isEmpty, peek, size 等操作。

顺序存储结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Stack {
// 是否为空
var isEmpty: Bool {
return stack.isEmpty
}

// 栈的大小
var size: Int {
return stack.count
}

// 栈顶元素
var peek: Int? {
return stack.last
}

// 入栈
func push(_ value: Int) {
stack.append(value)
}

// 出栈
func pop() -> Int? {
return stack.popLast()
}

private var stack: [Int] = []
}

链式存储结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Node {
var value: Int?
var next: Node?

init(_ value: Int?) {
self.value = value
self.next = nil
}
}

class Stack_Link {
private var head: Node? // 指向栈顶元素的指针

var isEmpty: Bool {
return head == nil
}

var size: Int {
get {
var count = 0

var node = head?.next
while node != nil {
count += 1
node = node?.next
}
return count
}
}

var peek: Node? {
return head?.next
}

func push(_ value: Int) {
if head == nil {
head = Node(nil)
}

let newNode = Node(value)

let lastTop = head?.next

newNode.next = lastTop
head?.next = newNode
}

func pop() -> Node? {
let top = head?.next
head?.next = top?.next
return top
}
}

队列

概念

  • 队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

  • 队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。

结构

对队列来说,一般我们只需要关注:enterQueue, outQueue, isEmpty, peek, size 等操作。

队列顺序存储结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Queue {
// 是否为空
var isEmpty: Bool {
return queue.isEmpty
}

// 队列的大小
var size: Int {
return queue.count
}

// 队头元素
var peek: Int? {
return queue.last
}

// 入队操作
func enterQueue(_ value: Int) {
queue.append(value)
}

// 出队操作
func outQueue() -> Int? {
if let element = queue.first {
queue.removeFirst()
return element
}
return nil
}

private var queue: [Int] = []
}

队列链式存储结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Node {
var value: Int?
var next: Node?

init(_ value: Int?) {
self.value = value
self.next = nil
}
}

class Queue_Link {
private var head: Node? // 指向队头
private var tail: Node? // 指向队尾

var isEmpty: Bool {
return head == nil && tail == nil
}

var size: Int {
get {
var count = 0

var node = head?.next
while node != nil {
count += 1
node = node?.next
}
return count
}
}

var peek: Node? {
return head?.next
}

func enterQueue(_ value: Int) {
let newNode = Node(value)
if head == nil {
head = Node(nil)
tail = Node(nil)
head?.next = newNode
tail?.next = newNode
} else {
let lastTail = tail?.next

lastTail?.next = newNode

tail?.next = newNode
}
}

func outQueue() -> Node? {
let top = head?.next

head?.next = top?.next

return top
}
}

互相实现

用栈实现队列

思路:因为栈的先进后出特性,需要完成先进先出的特点。我们需要用到两个栈,一个 enterStack,专门负责入队的操作,另一个 outStack,负责协助出队。当入队时,我们将新元素 push 到 enterStack 中,出队时分为两个步骤,先将 enterQueue 的元素 pop 出来,并将 pop 的元素加入到 outStack 中,此时 outStack 的栈顶元素就是最先入队的元素。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class ImplementQueueByStack {
private var enterStack = Stack()
private var outStack = Stack()

var isEmpty: Bool {
return enterStack.isEmpty && outStack.isEmpty
}

var size: Int {
return enterStack.size + outStack.size
}

var peek: Int? {
get {
tab()
return outStack.peek
}
}

func enterQueue(_ value: Int) {
enterStack.push(value)
}

func outQueue() -> Int? {
tab()
return outStack.pop()
}

// 将 enter 中的值,加入到 out 中
private func tab() {
if outStack.isEmpty {
while !enterStack.isEmpty {
outStack.push(enterStack.pop()!)
}
}
}
}

用队列实现栈

思路:根据栈实现队列的思路,这里我们也用两个队列来实现栈。一个 enterQueue,负责入栈,另一个 outQueue 负责协助出栈。入栈时,将新的元素加入到 enterQueue中,出栈时,也分为两个步骤,先将 enterQueue 中的元素出队至最后一个元素,并将所有出队的元素加入到 outQueue 中,此时,enterQueue 中剩下的元素即是我们需要出栈的元素。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class ImplementStackByQueue {
private var enterQueue = Queue()
private var tempQueue = Queue()

var isEmpty: Bool {
return enterQueue.isEmpty && tempQueue.isEmpty
}

var size: Int {
return enterQueue.size
}

var peek: Int? {
get {
tab()
let peekElement = enterQueue.peek
tempQueue.enterQueue(enterQueue.outQueue()!)
swap()
return peekElement
}
}

func push(_ value: Int) {
enterQueue.enterQueue(value)
}

func pop() -> Int? {
tab()
let popElement = enterQueue.outQueue()
swap()
return popElement
}

private func tab() {
while enterQueue.size != 1 {
tempQueue.enterQueue(enterQueue.outQueue()!)
}
}

private func swap() {
(enterQueue, tempQueue) = (tempQueue, enterQueue)
}
}