这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
基本数据结构
引言:本文本篇主要介绍的是几种比较基础并常见的数据结构:链表、栈以及队列。
栈
栈实现的是一种先入后出的策略,也就是先插入的元素最后被删除。在计算机中栈的实现方式有很多,这里我们简单用数组来实现。其结构类似如下:
其中先插入的元素放在栈底,后插入的放在栈顶。当要取元素的时候则取出栈顶的元素。可以用一个数组来表示栈,其中数组有一个top
属性,用来指向最新插入的元素。
在上图中,该数组就是一个栈,其中S.top指向栈顶,当要取出元素时候,先返回S.top
指向的元素,然后再S.top--
,而取出的元素还在数组中,但是其已经不在栈里面了。
关于数组栈的操作的伪代码如下:
//判断栈是否为空
STACK-EMPTY(S) // 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
return S[S.top--]
队列
队列和栈类似都是动态集合,不过队列实现的是一种先入先出的策略。队列的实现方式很多,这边还是采用数组来实现。队列的结构如下:
用数组来实现队列的话,需要两个指针,一个指向队尾一个指向队头,分别设为Q.tail
,Q.head
,当插入元素时Q.tail+1
,当取出元素时Q.head+1
当队列为空的时候则Q.tail==Q.head
,不过当队空的时候删除会导致下溢,队满的时候插入会导致上溢。所以需要判断是否溢出。
其队列的伪代码如下:
// 判断是否为空
QUEUE-EMPTY(Q)
if Q.tail==Q.head
return TRUE
return FALSE
QUEUE-FULL(Q)
if (Q.tail+1)%Q.size==Q.head
return TRUE
return FALSE
ENQUEUE(Q,x)
if QUEUE-FULL(Q)
error 'Overflow'
Q[Q.tail] = x
if Q.tail==Q.length
Q.tail = 1
else Q.tail = Q.tail+1
DEQUEUE(Q)
if QUEUE-EMPTY(Q)
error 'underflow'
x = Q[Q.head]
if Q.head = Q.length
Q.head = 1
else Q.head = Q.head+1
return x
链表
链表,别名链式存储结构或单链表,用于存储逻辑关系为 "一对一" 的数据。链表不限制数据的物理存储状态,即链表的顺序是随机的,其顺序由各个对象里面的指针决定。
链表主要由一个key
和next
以及一些卫星数据组成。当然在双向链表中,是由key
和next
以及prev
组成,其中next
和prev
分别是指向结点前一结点和后一结点的两个指针。而key
则是保存的数据.如果x.prev==NIL
则表示该结点为链表的头,x.next==NIL
则表示该结点为链表的尾。L.head
指向链表的头结点,其如果等于NIL
则表示链表为空.双向链表结构类似下图:
接下来介绍下,双向链表的插入删除和搜索:
搜索
链表的搜索采用线性搜索方式,查找某个关键字,然后返回该元素的指针。如果没有则返回NIL
。
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
删除
删除操作是先找到指定的指针,然后再通过修改一些指针,将x删除出链表。
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