在这篇文章中,我们介绍了两种在一个数组中设计K堆栈的方法。挑战在于如何有效地存储元素,以使用数组中的所有可用空间,并保持堆栈操作的时间复杂性。
目录:
- 简单的方法
- 高效的方法
让我们开始在一个数组中实现K堆栈。
简单的方法
在这个方法中,我们将创建一定大小的数组,并将该数组分成k个部分,用于存储k个堆栈的元素。
为了实现这一点,首先我们将创建两个大小为n的数组arr ,用于存储值
top 大小为k的数组用于存储堆栈的顶部位置
我们将用-1索引初始化Arr的所有元素,其中的-1被认为是空索引
并用堆栈的起始元素初始化顶层的元素。
例如:
让arr 是大小为9(n=9) 的数组,它将存储元素的值 。
top 大小为 的数组,它将存储堆栈的顶部位置。3(k=3)
栈的范围将是[(stack_no-1)*n/k, stack_no*n/k-1]
那么:
top[3]={0, 3, 6}
range of stack 1 = [0, 2]
range of stack 2 = [3, 5]
range of stack 1 = [6, 8]
如果第i个索引的值表示相应堆栈的顶部元素,其值将被存储在arr[i]
中:
arr={-1, -1, -1, -1}
top = {0, 2}
如果我们在栈1中输入1,在栈2中输入2,那么
arr = {1, -1, 2, -1}
top = {0, 2}
top[0] = 0 = top of 1st stack
top[1] = 2 = top of 2nd stack
现在,如果我们在第一栈中加入3,在第二栈中加入4 ,那么:
arr = {1, 3, 2, 4}
top = {1, 3}
top[0] = 1 = top of 1st stack
top[1] = 3 = top of 2nd stack
在堆栈中插入
- 对于插入,我们将使用
push函数 - 为了在堆栈中插入元素,首先我们将检查堆栈是否已满,如果是,我们将简单地打印堆栈已满
- 如果不是,则在堆栈的顶部添加值。
从堆栈中移出值
- 为了从堆栈中移出值,我们将使用
pop函数 - 为了从堆栈中移除元素,首先我们将检查堆栈是否为空,如果是,我们将简单地打印堆栈为空
- 否则,我们将从堆栈中移除值
push(int value, int stack_no)
-
如果top[stack_no](stack_no*n)/k和arr[top[stack_no]]-1,那么堆栈是空的[堆栈顶部等于堆栈的第一个索引,在arr的同一索引中的值是-1],所以我们可以在堆栈中加入插入元素
-
如果top[stack_no]+1<((stack_no+1)*n)/k,那么顶部元素旁边的索引是空的,我们可以在那里加值。所以我们首先将top[stack_no]增加1,然后我们将在arr[top[stack_no]]插入值
-
如果top[stack_no]>=((stack_no+1)*n)/k,那么我们将打印堆栈已满,因为((stack_no+1)*n)/k是堆栈的第一个元素,它在当前堆栈旁边
pop(int stack_no)
- 如果top[stack_no](stack_no*n)/k和arr[top[stack_no]]-1意味着栈顶等于栈的第一个索引,并且arr的相同索引的值是-1,因此栈是空的,所以我们将直接打印栈是空的,因为栈中没有元素存在
- 如果top[stack_no]==(stack_no*n)/k并且arr[top[stack_no]]!=-1意味着栈顶是栈的第一个索引,并且在当前栈的起始索引中有一些值,因此我们将返回栈顶的值并且在当前栈的起始索引的arr中存储-1。
- 如果top[stack_no]中的索引大于第一个索引,那么我们将返回索引top[stack_no]的arr中的值,在arr[index]的位置上存储-1,并将栈的一侧减少1。
代码
#include<iostream>
using namespace std;
class kstack{
int n, k;
int *arr, *top;
public:
kstack(int n, int k){
this->n = n; this->k = k;
arr = new int[n];
top = new int[k];
for(int i=0; i<n; i++) arr[i]=-1;
for(int i=0; i<k; i++) top[i] = (i*n)/k;
}
void push(int value, int stack_no){
stack_no--;
if(top[stack_no]==(stack_no*n)/k and arr[top[stack_no]]==-1) arr[top[stack_no]]=value;
else if(top[stack_no]+1<((stack_no+1)*n)/k and arr[top[stack_no]+1]==-1) top[stack_no]++, arr[top[stack_no]]=value;
else cout<<"Stack no "<<stack_no+1<<" is Full, can't enter "<<value<<endl;
}
int pop(int stack_no){
int temp=-1;
stack_no--;
if(top[stack_no]==(stack_no*n)/k and arr[top[stack_no]]==-1) cout<<"Stack no "<<stack_no+1<<" is Empty"<<endl;
else if(top[stack_no]==(stack_no*n)/k and arr[top[stack_no]]!=-1) temp=arr[top[stack_no]], arr[top[stack_no]]=-1;
else temp=arr[top[stack_no]], arr[top[stack_no]]=-1, top[stack_no]--;
return temp;
}
~kstack(){
delete [] arr;
delete [] top;
}
};
void solve(){
// Stack with k=2 and n=4
kstack k1(4, 2);
// Adding elements to stack 1
k1.push(1, 1);
k1.push(2, 1);
k1.push(3, 1);
// Adding elements to stack 2
k1.push(4, 2);
k1.push(5, 2);
k1.push(6, 2);
// Removing elements from Stack 1
cout<<k1.pop(1)<<endl;
cout<<k1.pop(1)<<endl;
cout<<k1.pop(1)<<endl;
// Removing elements from Stack 2
cout<<k1.pop(2)<<endl;
cout<<k1.pop(2)<<endl;
cout<<k1.pop(2)<<endl;
}
int main(){
solve();
return 0;
}
输出
Stack no 1 is Full, can't enter 3
Stack no 2 is Full, can't enter 6
2
1
Stack no 1 is Empty
-1
5
4
Stack no 2 is Empty
-1
时间复杂度
O(1)[所有的操作(pop和push)都在O(1)时间内执行] 。
空间复杂度
O(N)[因为我们使用两个数组,一个大小为n,另一个大小为k(k<=n),所以是O(N)] 。
高效的方法
在这个方法中,我们将创建三个数组:
- 数组
arr,用于存储堆栈元素 - 数组
top,用于存储堆栈的顶部索引 next用于存储指向下一个空闲空间的指针,也用于存储该堆栈顶部元素下面的元素索引
例子:让arr的大小为n
,那么对于一个索引0 <= i < n,
如果arr[i]将存储该元素的值,而next[i]将存储堆栈中该元素下面的索引。
但是如果arr[i]是空的或者没有分配给任何一个堆栈,那么next[i]将存储在索引i之后的下一个空闲空间。arr
我们将创建一个名为free 的变量来存储最小索引的空位。
我们将在类中实现这一点,并将完整的操作分给函数。
我们将创建大小为n的k的数组,并将所有元素初始化为-1。
n大小的下一个数组,用索引初始化每个元素,如果是下一个元素,则用-1初始化最后一个元素,用0初始化空位
例如:
n=4,k=2 ,则 空位=0
top[2]={-1,-1}
next[4]={1,2,3,-1}。
isEmpty(int stack_no)。
-
这个函数将检查堆栈是否为空。
-
如果堆栈的顶部是-1,那么堆栈就是空的,因为我们已经声明所有的元素都是-1。
isFull(int stack_no)
- 这个函数将检查堆栈是否已满
- 如果free是-1,那么堆栈是满的,因为free是最小的索引,如果free是-1,意味着free存储的是下一个数组的最后一个元素。
push(int value, int stack_no)
这个函数将被用来在堆栈中插入元素
- 首先检查堆栈是否已满,然后打印堆栈已满。
- 否则
- 将free的值存储在temp变量中,在arr的索引temp中我们将存储我们的值。
- 使用free = next[temp]将下一个空闲位置存储在free中。
- 存储temp,它是当前元素的索引,也是堆栈中的顶层元素,在顶层数组中。
pop(int stack_no)
这个函数将被用来从一个特定的堆栈中移除元素
- 首先我们将检查堆栈是否为空,如果是,我们将直接打印堆栈为空
- 否则
- 在temp中存储顶部元素的索引
- 使用next[temp]更新top与第二个top元素的索引
- 使用free变量用下一个空闲位置来更新temp
- 用temp作为索引更新free,temp刚刚得到free。
- 从arr中返回索引temp中的值
代码
#include<iostream>
using namespace std;
class kstack{
int n, k, free;
int *arr, *top, *next;
public:
kstack(int n, int k){
this->n = n;
this->k = k;
this->arr = new int[n];
this->top = new int[k];
for(int i=0; i<k; i++) top[i]=-1;
this->next = new int[n];
for(int i=0; i<n-1; i++) next[i]=i+1;
next[n-1]=-1;
this->free = 0;
}
bool isFull(){
if(free==-1) return true;
else return false;
}
bool isEmpty(int stack_no){
if(top[stack_no]==-1) return true;
else return false;
}
void push(int value, int stack_no){
stack_no-=1;
if(isFull()){
cout<<"Stack no "<<stack_no+1<<" is Full, can't enter "<<value<<endl;
return;
}
int temp = free;
free = next[temp];
next[temp] = top[stack_no];
top[stack_no] = temp;
arr[temp] = value;
}
int pop(int stack_no){
stack_no-=1;
if(isEmpty(stack_no)){
cout<<"Stack no "<<stack_no+1<<" is Empty"<<endl;
return -1;
}
int temp = top[stack_no];
top[stack_no] = next[temp];
next[temp] = free;
free = temp;
return arr[temp];
}
~kstack(){
delete [] arr;
delete [] top;
}
};
void solve(){
// Stack with k=2 and n=4
kstack k1(4, 2);
// Adding elements to stack 1
k1.push(1, 1);
k1.push(2, 1);
k1.push(3, 1);
// Adding elements to stack 2
k1.push(4, 2);
k1.push(5, 2);
k1.push(6, 2);
// Removing elements from Stack 1
cout<<k1.pop(1)<<endl;
cout<<k1.pop(1)<<endl;
cout<<k1.pop(1)<<endl;
// Removing elements from Stack 2
cout<<k1.pop(2)<<endl;
cout<<k1.pop(2)<<endl;
cout<<k1.pop(2)<<endl;
}
int main(){
solve();
return 0;
}
输出
Stack no 2 is Full, can't enter 5
Stack no 2 is Full, can't enter 6
3
2
1
4
Stack no 2 is Empty
-1
Stack no 2 is Empty
-1
时间复杂度
O(1)[所有的操作(pop和push)都在O(1)时间内完成] 。
空间复杂度
O(N)[因为我们使用三个数组,2个大小为n,1个大小为k(k<=n)]因此,O(N)] 。
通过OpenGenus的这篇文章,你一定对如何在一个数组中设计和实现K个堆栈有了完整的认识。