1.スタック(積み重ね)
1. スタックの概念:
スタックは、一方の端の要素の挿入と削除のみを許可する特別な線形リストです。データの挿入および削除操作が実行される端をスタックの最上位と呼び、もう一方の端をスタックの最下位と呼びます。スタック内のデータ要素は、LIFO (Last In First Out) の原則に従います。
2. スタックの実装
スタックの実装は一般に配列またはリンク リストを使用して実装できますが、比較的に配列の構造の方が優れています。配列にデータを末尾に挿入するコストが比較的小さいためです。
スタックへの継続的なプッシュにより、スタック内のデータも増加し、スタックへのプッシュおよびスタックからのポップアウトの操作はすべてスタックの最上部で実行されます。
//入栈
void push(T ele);
//出栈
T pop();
//查看顶部元素
T peek();
//栈是否为空
boolean isEmpty();
//栈中的元素
int size();
private selfArray<T> data;
public Arrstack() {
this.data = new selfArray<>();
}
public Arrstack(int capacity) {
this.data = new selfArray<>(capacity);
}
@Override
public void push(T ele) {
data.addlast(ele);
}
@Override
public T pop() {
return data.removeTail();
}
@Override
public T peek() {
return data.getindex(size() - 1);
}
@Override
public boolean isEmpty() {
return data.isEmpty();
}
@Override
public int size() {
return data.getSize();
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder("栈顶[");
T[] arr = data.getDate();
for (int i = data.getSize()-1; i >= 0; i--) {
stringBuilder.append(arr[i]);
}
stringBuilder.append("]栈底");
return stringBuilder.toString();
}
1. スタックにプッシュします (基礎となる配列の実装方法):
//向中间添加元素
public void addmid(T val,int index) {
//对入参进行判断
if(index<0||index>size){
throw new IllegalArgumentException("数组越界异常");
}
//判断此容器有没有满
if(this.size==this.capacity){
int newcapa = this.capacity*2;
reserve(newcapa);
}
//将指定的位置之后的元素向后移
for (int i = this.size-1; i >=index ; i--) {
this.data[i + 1] = this.data[i];
}
//将元素插入到指定位置
this.data[index]=val;
//更新size的值
this.size+=1;
}
2. ポップアウト:
//删除任意位置的元素
public T remove(int index){
if(index<0||index>=this.size){
throw new IllegalArgumentException("数组索引越界");
}
T a = this.data[index];
for (int i = index; i <size-1 ; i++) {
this.data[i]=this.data[i+1];
}
this.size-=1;
if(this.size<=this.capacity/4&&this.size>1){
int newcapa = this.capacity/2;
reserve(newcapa);
}
return a;
}
3. スタックの先頭にある要素を取得します
//获取指定位置的元素
public T getindex(int index){
if(index<0||index>=size){
throw new IllegalArgumentException("数组越界异常");
}
return this.data[index];
}
2. キュー
1.コンセプト
キューは線形データ構造です。キューはテーブルのフロントエンドでの削除操作と、テーブルのバックエンドでの挿入操作のみを許可します。スタックと同様に、キューは制限された操作を持つ線形テーブルです。挿入操作をチームの末尾と呼び、削除操作を実行する側をチームの先頭と呼びます。
2. コードの実装
1. 配列ベースの実装
//入队
void offer(T ele);
//出队
T poll();
//判断是否为空
boolean isEmpty();
//队中实际的元素
int size();
//查看对首的元素
T peek();
CycleArray<T> data;
public ArrQueue() {
this.data=new CycleArray<>();
}
public ArrQueue(int capacity){
this.data=new CycleArray<>(capacity);
}
@Override
public void offer(T ele) {
data.addtail(ele);
}
@Override
public T poll() {
return data.removeHead();
}
@Override
public boolean isEmpty() {
return data.isEmpty();
}
@Override
public int size() {
return data.getSize();
}
@Override
public T peek() {
Optional<T> optional = data.getFront();
if(optional.isPresent()){
return optional.get();
}
return null;
}
2. 循環キュー
配列内の要素を削除すると、要素は前に移動します。前に移動する問題を解決するには、frontを使用してキューの先頭の位置を記録し、tail を使用してキューの末尾の位置を記録します。キュー。これは循環キューです。 配列またはループ リンク リスト実装を使用して実装できます。
キーポイント: 循環キューは、配列で実装されるかリンク リストで実装されるかに関係なく、追加のスペースを開く必要があります。つまり、k データを格納する循環キューの場合は、k+1 スペースを開く必要があり、そうでない場合は、スペースを開くことができません。空か満かを判断できる
(1) 配列コードの実装
//数据容器
private T[] data;
//数组大小
private int capacity;
//数组实际存入的元素数量
private int size;
//声明两个索引 队首
int front=0;
//队尾
int tail=0;
public CycleArray() {
this(10);
}
public CycleArray(int capacity) {
this.capacity = capacity+1;
this.data = (T[]) new Object[this.capacity];
this.size = 0;
}
//判断数组是否为空
public boolean isEmpty() {
return this.front==this.tail;
}
//获取数组的大小
public int getCapacity() {
return this.capacity;
}
//获取实际元素的个数
public int getSize() {
return this.size;
}
//向尾部添加元素
public void addtail(T val){
//当队列已满,需要进行扩容
if((this.tail+1)%this.capacity==this.front){
//新容积
int Newcapa = (this.capacity-1)*2;
reserve(Newcapa);
}
//将val插入队列的尾部
this.data[this.tail]=val;
//tail向后移
this.tail=(this.tail+1)%capacity;
//更新size的值
this.size+=1;
}
public T[] getDate(){
return this.data;
}
//扩容
public void reserve(int Newcapa) {
T[]newdata = (T[])new Object[Newcapa+1];
int cur = this.front;
int index=0;
while (cur!=this.tail){
newdata[index++]=this.data[cur];
cur=(cur+1)%this.capacity;
}
//更新新数组的属性
this.capacity=Newcapa+1;
this.data=newdata;
this.front=0;
this.tail=this.size;
}
//删除头部的元素
public T removeHead(){
//判断队列是否为空
if(this.front==this.tail){
return null;
}
T val = this.data[this.front];
this.front=(this.front+1)%capacity;
this.size--;
//判断是否缩容
if(this.size<=this.capacity/4&&this.capacity/2>1){
reserve(this.capacity/2);
}
return val;
}
public Optional<T> getFront(){
if(isEmpty()){
return Optional.empty();
}
return Optional.of(this.data[this.front]);
}
//重写tostring
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
int cur = this.front;
while (cur!=this.tail){
stringBuilder.append(this.data[cur]);
if((cur+1)%this.capacity!=this.tail){
stringBuilder.append(",");
}
cur=(cur+1)%this.capacity;
}
stringBuilder.append(":"+this.front+"<--->"+this.tail);
return stringBuilder.toString();
}