3.1 用一个数组来实现三个栈

     《程序员面试金典》(第六版)习题:仅为记录一下以加强印象,不为商业用途,如有侵权请联系删除。以下源码和解释参考了书中源码以及解释。

class FixedMultiStack 
{
    public:
	   FixedMultiStack(size_t capacity)
	   {
	       stack_capacity = capacity;
	       //注意下面语句中的括号很重要,如果不加括号的话,分配的空间不会初始化,编译可能会有错误。加了括号NEW操作才会对分配的空间进行初始化//
		   values = new size_t[numOfstacks * stack_capacity]();
		   sizes = new size_t[numOfstacks]();
	   };

	   ~FixedMultiStack() 
	   {
	   	   delete [] values;
	   	   delete [] sizes;
	   };

	   bool isFull(size_t stackIndex) 
	   {
		   return sizes[stackIndex] == stack_capacity;
	   };

	   bool isEmpty(size_t stackIndex) 
	   {
		   return sizes[stackIndex] == 0;
	   };

	   size_t peek(size_t stackIndex)
	   {
		   assert(!isEmpty(stackIndex));
		   return values[indexOfTop(stackIndex)];
	   };

	   void push(size_t stackIndex, int value) 
	   {
		   assert(!isFull(stackIndex));
		   sizes[stackIndex]++;
		   values[indexOfTop(stackIndex)] = value;
	  };

	  int pop(size_t stackIndex) 
	  {
		   assert(!isEmpty(stackIndex));

		   size_t topIndex = indexOfTop(stackIndex);
		   int value = values[topIndex];
		   values[topIndex] = 0;

		   sizes[stackIndex]--;

		   return value;
	   };
	  void prinFixedtStack()
	  {
		  for (int stackIndex = 0; stackIndex < numOfstacks; stackIndex++)
		  {
			  cout << "Stack " << stackIndex << " is:"<<endl;
			  size_t offset = stackIndex * stack_capacity;
			  for (int valueIndex = 0; valueIndex < sizes[stackIndex]; valueIndex++)
			  {
				  cout << values[offset + valueIndex] << " ";
			  }
			  cout << endl;
		  }
	  }
	  size_t numberOfstacks()
	  {
		  return numOfstacks;
	  }

    private:
	   size_t numOfstacks=3;
	   size_t stack_capacity;
	   size_t* values;
	   size_t* sizes;

	   size_t indexOfTop(size_t stackIndex)
	   {
		   size_t offset = stackIndex * stack_capacity;
		   size_t size = sizes[stackIndex];
		   return offset + size - 1;
	   };
};

    这里的算法在一个数组里实现了三个栈,三个栈的大小相同并且建立之后栈的大小不可扩充。三个栈均匀的分布在数组的前、中、后部。以下是测试程序及结果。

int main()
{
	FixedMultiStack testStack(10);
	testStack.push(0, 7);
	testStack.push(1, 8);
	testStack.push(2, 9);
	testStack.prinFixedtStack();
	testStack.push(0, 10);
	testStack.push(1, 11);
	testStack.push(2, 12);
	testStack.prinFixedtStack();
	for (int stackIndex = 0; stackIndex < testStack.numberOfstacks(); stackIndex++)
	{
		cout << "The top of stack "<< stackIndex<<" is "<< testStack.peek(stackIndex)<<endl;
	}
	testStack.pop(0);
	testStack.pop(1);
	testStack.pop(2);
	testStack.prinFixedtStack();
	testStack.pop(0);
	testStack.pop(1);
	testStack.pop(2);
	testStack.prinFixedtStack();
	return 0;
}
 
图1.

    下面的算法同样在一个数组中实现了三个栈,三个栈的总的空间在分配后不可以改变,但是单个栈的大小是可以变化的。算法的关键部分在于当其中一个栈的空间已满,但是三个栈整个空间还没有满时,可以通过移动数据来调整空间还没有满的栈的数据位置和该栈的空间大小以此来扩充已满的栈的空间来存放额外的数据。这一关键部分对应于函数 v o i d    s h i f t S t a c k ( i n t    s t a c k I n d e x ) ; void \; shiftStack(int \; stackIndex); voidshiftStack(intstackIndex); v o i d    e x p a n d ( i n t    s t a c k I n d e x ) ; void \; expand(int \;stackIndex); voidexpand(intstackIndex);
    该算法的另一个重点是,算法将数组在逻辑上考虑为一个链接起来的环形结构,这里就涉及到索引的处理问题,例如数组的0索引等同于索引9和索引-9,但是我们访问数组时肯定还是按照正常的数组索引,这里的关键代码对应于函数 i n t    a d j u s t I n d e x ( i n t    i n d e x , i n t    s t a c k A r r a y L e n g t h ) int \;adjustIndex(int \;index,int \;stackArrayLength) intadjustIndex(intindex,intstackArrayLength)和与此函数功能相对的代码。逻辑上第三个栈可以向第一个栈扩充,如图2所示。在执行语句 t e s t S t a c k . p u s h ( 2 , 48 ) ; testStack.push(2, 48); testStack.push(2,48);时,第三个栈的空间不够,但是此时第一个栈有一个可用空间,因此此时移动第一个栈中的数据并减小该站的容量,将空出的容量来扩充第三个栈。扩充完第三个栈之后,如果不对索引进行特殊处理,计算得出存储进栈值的数组索引为 s t a r t + s i z e − 1 = 6 + 4 − 1 = 9 start+size-1=6+4-1=9 start+size1=6+41=9。如果按照该索引去访问栈数组,就越界了,对该索引处理完之后的值为 a d j u s t I n d e x ( s t a r t + s i z e − 1 , s t a c k A r r a y L e n g t h ) = 0 ; adjustIndex(start + size - 1, stackArrayLength)=0; adjustIndex(start+size1,stackArrayLength)=0;,这下就对了。接下来的进栈操作索引处理方式类似,只不过需要移动两个栈的数据而已。

 
图2.
class StackInfo
{
    public:
	    StackInfo(int st = 0, int ca = 0, int si = 0)
	    {
		    start = st;
		    capacity = ca;
			size = si;
	    }

	    bool isWithinStackCapacity(int index, int stackArrayLength)
	    {
	    	if (index < 0 || index >= stackArrayLength)
	    	{
	    		return false;
	    	}
	    	int contiguousIndex = index < start ? index + stackArrayLength : index;
	    	int end = start + capacity;
	    	return start <= contiguousIndex && contiguousIndex < end;
	    
	    }
	    int lastCapacityIndex(int stackArrayLength)
	    {
	    	return adjustIndex(start + capacity - 1, stackArrayLength);
	    }
	    int lastElementIndex(int stackArrayLength)
	    {
	    	return adjustIndex(start + size - 1, stackArrayLength);
	    }
	    bool isFull()
	    {
	    	return size == capacity;
	    };
	    
	    bool isEmpty()
	    {
	    	return size == 0;
	    };
		int getSize()
		{
			return size;
		}
		void setSize(int value)
		{
			 size=value;
		}
		int getStart()
		{
			return start;
		}
		void setStart(int newstart)
		{
			start= newstart;
		}
		int getCapacity()
		{
			return capacity;
		}
		void setCapacity(int value)
		{
			capacity = value;
		}
    private:
	    int start;
	    int size;
	    int capacity;
		int adjustIndex(int index,int stackArrayLength)
		{
			return ((index % stackArrayLength) + stackArrayLength) % stackArrayLength;
		};

};
class FlexibleMultiStack 
{
    private:
		StackInfo* info;
		int* values;
		int valuesLength;
		int numOfstacks;
		int previousIndex(int index)
		{
			return (((index-1) % valuesLength) + valuesLength) % valuesLength;
		}
		int nextIndex(int index)
		{
			return(((index + 1) % valuesLength) + valuesLength) % valuesLength;
		}
		void shiftStack(int stackIndex)
		{
			if (info[stackIndex].isFull())
			{
				shiftStack((stackIndex + 1) % numOfstacks);
				int currentCapacity = info[stackIndex].getCapacity();
				currentCapacity = currentCapacity + 1;
				info[stackIndex].setCapacity(currentCapacity);
			}
			int index = info[stackIndex].lastCapacityIndex(valuesLength);
			while(info[stackIndex].isWithinStackCapacity(index, valuesLength))
			{
				values[index] = values[previousIndex(index)];
				index = previousIndex(index);
			}
			values[info[stackIndex].getStart()] = 0;
			info[stackIndex].setStart((((info[stackIndex].getStart() + 1) % valuesLength) + valuesLength) % valuesLength);
			info[stackIndex].setCapacity(info[stackIndex].getCapacity()-1);
		}
		void expand(int stackIndex)
		{
			shiftStack((stackIndex+1)% numOfstacks);
			int currentCapacity=info[stackIndex].getCapacity();
			currentCapacity = currentCapacity + 1;
			info[stackIndex].setCapacity(currentCapacity);
		};
    public:
		FlexibleMultiStack(int stackNum,int defaultCapacity)
	    {
		   numOfstacks = stackNum;
		   valuesLength = numOfstacks * defaultCapacity;
		   info = new StackInfo[numOfstacks];
		   for (int stackIndex = 0; stackIndex < numOfstacks; stackIndex++)
		   {
			   StackInfo * temp = new StackInfo(stackIndex * defaultCapacity, defaultCapacity);
			   info[stackIndex] = *temp;
			   delete temp;
		   }
		   values = new int[numOfstacks * defaultCapacity]();
	    };

	   ~FlexibleMultiStack()
	   {
	   	   delete [] values;
	   	   delete [] info;
	   };

	   int numberOfElements()
	   {
		   int num = 0;
		   for (int stackIndex=0;stackIndex< numOfstacks; stackIndex++)
		   {
			   num += info[stackIndex].getSize();

		   }
		   return num;
	   }

	   bool allStacksAreFull()
	   {
		   return numberOfElements() == valuesLength;
	   }


	   int peek(int stackIndex)
	   {
		   assert(!info[stackIndex].isEmpty());
		   return values[info[stackIndex].lastElementIndex(valuesLength)];
	   };

	   void push(int stackIndex, int value) 
	   {
		   assert(!allStacksAreFull());
		   if (info[stackIndex].isFull())
		   {
			   expand(stackIndex);
		   }
		   info[stackIndex].setSize(info[stackIndex].getSize()+1);
		   values[info[stackIndex].lastElementIndex(valuesLength)] = value;
	  };

	  int pop(int stackIndex) 
	  {
		   assert(!info[stackIndex].isEmpty());

		   int value = values[info[stackIndex].lastElementIndex(valuesLength)];
		   values[info[stackIndex].lastElementIndex(valuesLength)] = 0;

		   info[stackIndex].setSize(info[stackIndex].getSize() - 1);

		   return value;
	   };
	  void printFlexibleStack()
	  {
		  for (int stackIndex = 0; stackIndex < numOfstacks; stackIndex++)
		  {
			  cout << "Stack " << stackIndex << " is:"<<endl;
			  for (int valueIndex = info[stackIndex].getStart(); valueIndex < (info[stackIndex].getStart()+ info[stackIndex].getSize()); valueIndex++)
			  {
				  cout << values[valueIndex] << " ";
			  }
			  cout << endl;
			  cout << "start value is: " << info[stackIndex].getStart() << endl;
			  cout << "size value is: " << info[stackIndex].getSize() << endl;
			  cout << "capacity value is: " << info[stackIndex].getCapacity() << endl;
		  }
	  }
	  int numberOfstacks()
	  {
		  return numOfstacks;
	  }
};
//测试代码
int main()
{
	FlexibleMultiStack testStack(3,3);
	testStack.push(0, 7);
	testStack.push(1, 8);
	testStack.push(2, 9);
	testStack.printFlexibleStack();
	testStack.push(0, 10);
	testStack.push(1, 11);
	testStack.push(2, 12);
	testStack.printFlexibleStack();
	testStack.push(0, 80);
	testStack.push(1, 81);
	testStack.push(2, 82);
	testStack.printFlexibleStack();
	for (int stackIndex = 0; stackIndex < testStack.numberOfstacks(); stackIndex++)
	{
		cout << "The top of stack "<< stackIndex<<" is "<< testStack.peek(stackIndex)<<endl;
	}
	testStack.pop(0);
	testStack.pop(1);
	testStack.pop(2);
	testStack.printFlexibleStack();
	testStack.push(0, 180);
	testStack.push(0, 280);
	testStack.push(0, 380);
	testStack.printFlexibleStack();
	return 0;
}

    测试结果如图3所示。

 
图3.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qqssss121dfd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值