栈
|----------|-------------------------------------------------------|
| 定义 | 栈是一种后进先出的线性表,要求所有的数据插入和删除都只在表的同一端进行。这一端被称为栈顶,另一端称为栈底。 |
| 特点 | 后进先出 |
| 主要操作 | 1、入栈 2、出栈 3、读取栈顶元素 |
顺序栈
cs
public class MyStack<T> where T : struct
{
private T[] array;
private int _count;
private int _capacity;
public int Count => _count;
public int Capacity => _capacity;
//栈初始化
public MyStack(int size)
{
if (size <= 0)
{
throw new Exception("容量必须大于0");
}
array = new T[size];
_capacity = size;
_count = 0;
}
//入栈
public void Push(T value)
{
if (_count >= _capacity)
{
throw new Exception("容量不够");
return;
}
array[_count] = value;
_count++;
}
//出栈
public T Pop()
{
if (_count == 0)
{
throw new Exception("容量不够");
return default;
}
var value = array[_count - 1];
array[_count - 1] = default;
_count--;
return value;
}
//获取栈顶元素
public T Peek()
{
if (_count == 0)
{
throw new Exception("容量不够");
return default;
}
return array[_count - 1];
}
//从栈顶开始打印栈
public void Print()
{
var str = "";
str += $"栈中元素个数:{_count} 容量为:{_capacity}\n";
for (var i = _count - 1; i >= 0; i--)
{
str += $"{array[i]} ";
}
Debug.Log(str);
}
}
链栈
cs
//链栈
public class LinkStack<T> where T : struct
{
public class LinkNode
{
public T value;
public LinkNode nextNode;
public LinkNode(T _value)
{
value = _value;
}
}
private LinkNode headNode;//头结点
private int _count;
public int Count => _count;
public LinkStack()
{
headNode = new LinkNode(default);
}
//入栈
public void Push(T value)
{
var targetNode = GetNodeByIndex(0);
var newNode = new LinkNode(value);
if (targetNode == null)
{
headNode.nextNode = newNode;
}
else
{
newNode.nextNode = targetNode;
headNode.nextNode = newNode;
}
_count++;
}
//出栈
public bool Pop(out T result)
{
var targetNode = GetNodeByIndex(1);
if (targetNode == null)
{
result = default;
return false;
}
result = headNode.nextNode.value;
headNode.nextNode = targetNode;
_count--;
return true;
}
//读取栈顶元素
public bool Peek(out T result)
{
var targetNode = GetNodeByIndex(0);
if (targetNode == null)
{
result = default;
return false;
}
result = targetNode.value;
return true;
}
//打印链栈中数据
public void Print()
{
string str = "";
ReadLinkList(ref str, headNode.nextNode);
Console.WriteLine($"数据个数:{_count} 链栈元素:{str}");
}
private void ReadLinkList(ref string str, LinkNode node)
{
if (node == null)
{
return;
}
str += $"{node.value} ";
ReadLinkList(ref str, node.nextNode);
}
//获取链表中指定索引的节点
private LinkNode GetNodeByIndex(int index)
{
if (index < 0 || index >= _count)
{
return null;
}
var linkNode = headNode.nextNode;
for (var i = 0; i < _count; i++)
{
if (index == i)
{
return linkNode;
}
else
{
linkNode = linkNode.nextNode;
}
}
return null;
}
}
队列
|------|-------------------------------------------------------------------|
| 定义 | 队列是一种先进先出的线性表,要求所有的数据插入在表的一端进行,而删除在表的另一端进行。进行插入的一端叫队尾,进行删除的一端叫队头。 |
| 特点 | 先进先出 |
| 主要操作 | 1、入队 2、出队 3、读取队头元素 |
普通队列

使用链表实现
cs
//链队
public class LinkQueue<T> where T : struct
{
public class LinkNode
{
public T value;
public LinkNode nextNode;
public LinkNode(T _value)
{
value = _value;
}
}
private LinkNode headNode;//头结点
private int _count;
public int Count => _count;
public LinkQueue()
{
headNode = new LinkNode(default);
}
//入队
public void Enqueue(T value)
{
var targetNode = GetNodeByIndex(_count - 1);
var newNode = new LinkNode(value);
if (targetNode == null)
{
headNode.nextNode = newNode;
}
else
{
targetNode.nextNode = newNode;
}
_count++;
}
//出队
public bool Dequeue(out T result)
{
var targetNode = GetNodeByIndex(1);
if (targetNode == null)
{
result = default;
return false;
}
result = headNode.nextNode.value;
headNode.nextNode = targetNode;
_count--;
return true;
}
//读取队头元素
public bool Peek(out T result)
{
var targetNode = GetNodeByIndex(0);
if (targetNode == null)
{
result = default;
return false;
}
result = targetNode.value;
return true;
}
//打印队列中数据
public void Print()
{
string str = "";
ReadLinkList(ref str, headNode.nextNode);
Console.WriteLine($"数据个数:{_count} 队列元素:{str}");
}
private void ReadLinkList(ref string str, LinkNode node)
{
if (node == null)
{
return;
}
str += $"{node.value} ";
ReadLinkList(ref str, node.nextNode);
}
//获取链表中指定索引的节点
private LinkNode GetNodeByIndex(int index)
{
if (index < 0 || index >= _count)
{
return null;
}
var linkNode = headNode.nextNode;
for (var i = 0; i < _count; i++)
{
if (index == i)
{
return linkNode;
}
else
{
linkNode = linkNode.nextNode;
}
}
return null;
}
}
循环队列
循环队列是一种使用固定大小的数组 ,并将数组在逻辑上视为一个环状结构的队列。
它的核心逻辑是使用两个指针(或索引):
front(队首):指向队列中的第一个元素。
rear(队尾):指向队列中下一个可以插入元素的位置。
基本操作逻辑
1、创建一个固定大小的数组。
将 front 和 rear 都初始化为 0。
2、入队
将新元素放入 rear 所指向的位置。然后,rear 指针不是简单地加1,而是通过一个取模运算向后移动:rear = (rear + 1) % capacity(capacity 是数组的总容量)。
这个取模操作是关键,它使得当 rear 到达数组末尾时,下一个位置会"绕回"到数组的开头,形成一个循环。
3、出队
返回 front 所指向的元素。然后,front 指针同样通过取模运算向后移动:front = (front + 1) % capacity。
4、判空
当 front == rear 时,队列为空。
5、判满
这是循环队列的一个关键点。因为 front 和 rear 在循环中移动,rear 有可能追上 front。
判断队列为满的条件是:(rear + 1) % capacity == front。
注意:为了区分"空"和"满"的情况,我们有意牺牲了一个存储单元。也就是说,一个容量为 n 的循环队列,最多只能存放 n-1 个元素。如果不这样做,当队列满时,front 和 rear 也会相等,就和队列为空的条件冲突了。
操作图示
1、初始化

2、入队元素1

3、依次入队2、3、4

4、出队第一个元素

5、再次入队两个元素即达满队


代码实现
cs
public class CycleQueue<T> where T:struct
{
private T[] array;
private int _count;
private int _capacity;
private int front;//队首游标
private int rear;//队尾游标
public int Count => _count;
public int Capacity => _capacity;
//队列初始化
public CycleQueue(int size)
{
if (size <= 0)
{
throw new Exception("容量必须大于0");
}
array = new T[size];
_capacity = size;
_count = 0;
front = 0;
rear = 0;
}
public bool Enqueue(T value)
{
if (IsFullQueue())
{
Debug.LogError("满了!");
return false;
}
array[rear] = value;
rear = (rear + 1) % _capacity;
_count++;
return true;
}
public bool Dequeue(out T value)
{
if (IsEmptyQueue())
{
Debug.LogError("队伍为空!");
value = default;
return false;
}
value = array[front];
array[front] = default;
front = (front + 1) % _capacity;
_count--;
return true;
}
//获取队头元素
public T Peek()
{
if (_count == 0)
{
throw new Exception("队列为空!");
return default;
}
return array[front];
}
//判断是否为空队
public bool IsEmptyQueue()
{
return front == rear;
}
//判断是否为满队
public bool IsFullQueue()
{
return (rear + 1) % _capacity == front;
}
//打印循环队列
public void Print()
{
var str = "";
str += $"队列中元素个数:{_count} 容量为:{_capacity}\n";
var flag = front;
while (flag != rear)
{
str += $"{array[flag]} ";
flag = (flag + 1) % _capacity;
}
Debug.Log(str);
}
}
双端队列
双端队列是一种允许从两端进行插入和删除操作的线性数据结构。它结合了栈和队列的特性。

|---------|-------------|
| 在前端添加元素 | AddFirst |
| 在后端添加元素 | AddLast |
| 从前端删除元素 | RemoveFirst |
| 从后端删除元素 | RemoveLast |
| 查看前端元素 | PeekFirst |
| 查看后端元素 | PeekLast |
cs
//双端队列
public class DoubleQueue<T> where T : struct
{
public class LinkNode
{
public T value;
public LinkNode lastNode;
public LinkNode nextNode;
public LinkNode(T _value)
{
value = _value;
}
}
private LinkNode headNode;//队头结点
private LinkNode tailNode;//队尾结点
private uint _count;
public uint Count => _count;
public DoubleQueue()
{
headNode = new LinkNode(default);
tailNode = new LinkNode(default);
headNode.nextNode = tailNode;
tailNode.lastNode = headNode;
}
//从前端为队头,读取首元素
public bool PeekFirst(out T value)
{
var isEmpty = _count == 0;
value = isEmpty ? default : headNode.nextNode.value;
return !isEmpty;
}
//以后端为队头,读取首元素
public bool PeekLast(out T value)
{
var isEmpty = _count == 0;
value = isEmpty ? default : tailNode.lastNode.value;
return !isEmpty;
}
//从队头添加数据
public void AddFirst(T value)
{
var newNode = new LinkNode(value);
if (_count == 0)
{
headNode.nextNode = newNode;
newNode.lastNode = headNode;
newNode.nextNode = tailNode;
tailNode.lastNode = newNode;
}
else
{
var next = headNode.nextNode;
headNode.nextNode = newNode;
newNode.lastNode = headNode;
newNode.nextNode = next;
next.lastNode = newNode;
}
_count++;
}
//从队尾添加数据
public void AddLast(T value)
{
var newNode = new LinkNode(value);
if (_count == 0)
{
headNode.nextNode = newNode;
newNode.lastNode = headNode;
newNode.nextNode = tailNode;
tailNode.lastNode = newNode;
}
else
{
var last = tailNode.lastNode;
last.nextNode = newNode;
newNode.lastNode = last;
newNode.nextNode = tailNode;
tailNode.lastNode = newNode;
}
_count++;
}
//从队头出队
public bool RemoveFirst(out T result)
{
if(_count == 0)
{
result = default;
return false;
}
else
{
result = headNode.nextNode.value;
var next = headNode.nextNode.nextNode;
headNode.nextNode = next;
next.lastNode = headNode;
_count--;
return true;
}
}
//从队尾出队
public bool RemoveLast(out T result)
{
if (_count == 0)
{
result = default;
return false;
}
else
{
result = tailNode.lastNode.value;
var last = tailNode.lastNode.lastNode;
tailNode.lastNode = last;
last.nextNode = tailNode;
_count--;
return true;
}
}
//打印双端队列中数据
public void Print()
{
string str = "";
ReadLinkList(ref str, headNode.nextNode);
Console.WriteLine($"数据个数:{_count} 列表:{str}");
}
private void ReadLinkList(ref string str, LinkNode node)
{
if (node == tailNode) return;
str += $"{node.value} ";
ReadLinkList(ref str, node.nextNode);
}
}
