数据结构
本文简单介绍栈,队列,链表几种基本结构
1. 栈 (stack)
在栈内,被删除的是最近插入的元素,是一种后进先出的策略, 栈上的INSERT操作为压入(PUSH),DELETE操作为弹出(POP)。
下溢: 试图对一个空栈执行弹出操作。
上溢: 试图对一个满栈执行压入操作。
伪代码
STACK-EMPTY(S)
if S.top == 0
return true
else
return false
PUSH(S, x)
S.top = S.top + 1
S[S.top] = x
POP(S)
if STACK_EMPTY(S)
error "underflow"
else S.top = S.top - 1
return S[S.top + 1]
问题:
- 说明如何在一个数组A[1…n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢 ???
2. 队列(queue)
在队列中,被删去的总是集合中存在时间在场的元素,是一种先进先出的策略,栈上的INSERT操作为入队(ENQUEUE),DELETE操作为出队(DEQUEUE)。
队头(head): 队列的队头。
队尾(tail): 队列的队尾。
伪代码
利用数组Q[1…n],假设n = Q.length
ENQUEUE(Q, x)
Q[Q.tail] = x
if Q.tail == Q.length
Q.tail = 1
else Q.tail = Q.tail + 1
DEQUEUE(Q)
x = Q[Q.head]
if Q.head == 1
Q.head = 1
else Q.head = Q.head + 1
return x
问题
- 如何使用两个栈实现一个队列 ?如何使用两个队列实现一个栈???
3.链表(linked list)
链表每个元素都是一个对象,每个对象按线性顺序排列。
双向链表: 每个元素都是一个对象,每个对象有关键字key和两个指针: prev和next。 假设x为链表的一个元素,x.next 指向链表中的后继元素,x.prev 指向它在链表的前面元素,如果x.prev=NIL,则x是链表中的第一个元素(链表的头),x.next=NIL,则x是链表中的最后一个元素(链表的尾),属性L.head 指向链表的第一个元素,如果L.head=NIL,则链表为空。
单向链表: 则省略每个元素的prev指针。
循环链表: 是表头元素的prev指针执行表尾元素,表尾元素的next指针指向表头元素。
伪代码
链表的搜索
LIST-SEARCH(L,k)
x = L.head
while x ≠ NIL and x.key ≠ k
x = x.next
return x
链表的插入(插入到最前端)
LIST-INSERT(L, x)
x.next = L.head
if L.head ≠ NIL
L.head.prev = x
L.head = x
x.prev = NIL
链表的删除
LIST-DELETE(L, X)
if x.prev ≠ NIL
x.prev.next = x.next
else L.head = x.next
if x.next ≠ NIL
x.next.prev = x.prev
问题
- 如何用一个单链表L实现一个栈?如何用一个单链表实现一个队列?
4. 问题思路
-
数组的首部作为一个栈的栈底,数组的尾部可以作为一个另外一个栈的栈底,像中间移动。
-
两个栈实现一个队列: 将stack1作为存储区,stack2作为缓冲区,入队时,直接压入stack1中,出队时,判断stack2是否为空,如果如果stack2为空,则将stack1中的元素倒入stack2中,否则直接弹出stack2中的元素
两个队列实现一个栈: 将queue1作为入栈,queue2作为中转,入栈时,直接入队queue1,出栈时,将queue1中的处最后的元素的其他的元素入队queue2,queue1的元素视为出栈的元素,然后将queue2中的元素入队到queue1.1
-
实现队列: 入队方式为单链表尾插,出队方式为单链表头删。
实现栈: 每次入栈将元素放在头节点后面,出栈之间找到头节点指向的元素