1、数据存储和访问原则
栈(Stack):
存储原则:后进先出(LIFO,Last In First Out)。即最后加入的元素最先被移除。
访问方式:只能访问栈顶元素。栈的插入(push)和删除(pop)操作都只能在栈顶进行。
队列(Queue):
存储原则:先进先出(FIFO,First In First Out)。即最早加入的元素最先被移除。
访问方式:队列的插入操作(enqueue)在队尾进行,删除操作(dequeue)在队首进行。可以访问队首和队尾的元素,但通常不直接访问队列中间的元素。
数组(Array):
存储原则:元素在内存中连续存储,通过索引进行访问。
访问方式:随机访问。可以通过索引在常数时间内访问数组中的任意元素。
2、 数据操作
栈:
主要操作:push(入栈)、pop(出栈)、peek(查看栈顶元素但不移除)、isEmpty(判断栈是否为空)、size(获取栈的大小)。
队列:
主要操作:enqueue(入队)、dequeue(出队)、front(查看队首元素但不移除)、rear(查看队尾元素,但并非所有队列实现都提供此操作)、isEmpty(判断队列是否为空)、size(获取队列的大小)。
数组:
主要操作:通过索引进行元素的插入、删除、访问、遍历等。数组的大小在初始化时确定,一旦创建,其大小不能改变(尽管有些编程语言提供了动态数组的实现,如Java的ArrayList,但这在底层可能是通过数组扩容等方式实现的)。
3、应用场景
栈:
常用于需要后进先出操作的场景,如函数调用、括号匹配、浏览器历史记录、撤销操作等。
队列:
常用于需要按先后顺序处理数据的场景,如任务队列、打印机队列、消息队列、广度优先搜索(BFS)等。
数组:
适用于需要频繁访问元素、对内存空间要求较小的场景。由于数组在内存中是连续存储的,因此可以通过索引快速访问任意位置的元素。但是,数组的插入和删除操作可能会涉及大量元素的移动,因此在需要频繁进行插入和删除操作的场景下,数组可能不是最佳选择。
4、性能特点
栈和队列:
在大多数情况下,栈和队列的插入、删除和访问操作都可以在O(1)时间复杂度内完成,因为它们通常只涉及栈顶或队首、队尾的操作。
数组:
访问操作的时间复杂度为O(1),因为可以通过索引直接访问。但是,插入和删除操作的时间复杂度可能较高,特别是当需要在数组中间插入或删除元素时,可能需要移动大量元素。