如何用一个数组实现3个堆栈?

时间:2011-01-22 21:13:57

标签: algorithm data-structures stack

有时候,我遇到了以下面试问题:如何用一个数组实现3个堆栈?当然,任何静态分配都不是解决方案。

19 个答案:

答案 0 :(得分:80)

空间(非时间)效率。你可以:

1)定义从阵列端点开始并以相反方向增长的两个堆栈。

2)将第三个堆栈定义为从中间开始并沿任何方向生长。

3)重新定义Push op,这样当操作将覆盖其他堆栈时,在推送之前将整个中间堆栈向相反方向移动。

您需要存储前两个堆栈的堆栈顶部,以及某些结构中第三个堆栈的开头和结尾。

修改

alt text

上面你可能会看到一个例子。虽然可以根据您的问题启发式选择其他策略,但是使用相等的空间分区策略进行转换。

修改

按照@ ruslik的建议,中间堆栈可以使用交替序列实现后续推送。生成的堆栈结构类似于:

  

| Elem 6 | Elem 4 | Elem 2 | Elem 0 | Elem 1 | Elem 3 | Elem 5 |

在这种情况下,您需要在中间堆栈上存储n个元素并使用该函数:

f[n_] := 1/4 ( (-1)^n (-1 + 2 n) + 1) + BS3  

知道要用于此堆栈的下一个数组元素。

虽然这可能会导致更少的转移,但是三个堆栈的实现并不均匀,并且不均匀性(您知道)导致特殊情况,更多错误和维护代码的困难。

答案 1 :(得分:9)

只要您尝试将一个堆栈中的所有项目排列在阵列的一个“末端”,就会缺少第三个堆栈的空间。

但是,您可以“散布”堆栈元素。第一个堆栈的元素位于索引i * 3,第二个堆栈的元素位于索引i * 3 + 1,第三个堆栈的元素位于索引i * 3 + 2(其中i是整数)。

+----+----+----+----+----+----+----+----+----+----+----+----+----+..
| A1 : B1 : C1 | A2 : B2 : C2 |    : B3 | C3 |    : B4 :    |    :  
+----+----+----+----+----+----+----+----+----+----+----+----+----+..
                  ^                        ^         ^
                  A´s top                  C´s top   B´s top

当然,这种方案会浪费空间,特别是当堆栈的大小不等时。您可以创建类似于上述方案的任意复杂方案,但不知道对提出的问题有任何更多限制,我将在此处停止。

<强>更新

由于下面的评论确实有一个非常好的观点,因此应该补充说,没有必要进行散布,与更简单的内存布局相比,甚至可能会降低性能,如下所示:

+----+----+----+----+----+----+----+----+----+----+----+----+----+..
| A1 : A2 :    :    :    | B1 : B2 : B3 : B4 :    | C1 : C2 : C3 :  
+----+----+----+----+----+----+----+----+----+----+----+----+----+..
       ^                                  ^                    ^
       A´s top                            B´s top              C´s top

即。给每个堆栈它自己的连续内存块。如果真正的问题确实是如何尽可能最好地使用固定数量的内存,为了不限制每个堆栈超过必要的数量,那么我的答案将不会非常有用。

在这种情况下,我会选择@belisarius' answer:一个堆栈进入内存区域的“底部”端,“向上”增长;另一个堆栈进入内存区域的“顶部”端,向下“增长”,一个堆栈位于中间,在任何方向上增长,但是当它太靠近其他堆栈之一时能够移动。

答案 2 :(得分:8)

为所有三个筹码维持一个竞技场。推入堆栈的每个元素都有一个指向其前一个元素的向后指针。每个堆栈的底部都有一个指向NULL / None的指针。

竞技场维护指向可用空间中下一个项目的指针。推送将此元素添加到相应的堆栈,并将其标记为不再位于空闲空间中。弹出窗口从相应的堆栈中删除元素并将其添加到空闲列表中。

从这个草图中,堆栈中的元素需要一个反向指针和数据空间。自由空间中的元素需要两个指针,因此自由空间被实现为双向链表。

包含三个堆栈的对象需要一个指向每个堆栈顶部的指针以及一个指向空闲列表头部的指针。

此数据结构使用所有空间并在恒定时间内推送和弹出。堆栈中的所有数据元素都有单个指针的开销,空闲列表元素使用最大值(两个指针,一个指针+一个元素)。


后来:python代码就是这样的。注意使用整数索引作为指针。

class StackContainer(object):
    def __init__(self, stack_count=3, size=256):
        self.stack_count = stack_count
        self.stack_top = [None] * stack_count
        self.size = size
        # Create arena of doubly linked list
        self.arena = [{'prev': x-1, 'next': x+1} for x in range(self.size)]
        self.arena[0]['prev'] = None
        self.arena[self.size-1]['next'] = None
        self.arena_head = 0

    def _allocate(self):
        new_pos = self.arena_head
        free = self.arena[new_pos]
        next = free['next']
        if next:
            self.arena[next]['prev'] = None
            self.arena_head = next
        else:
            self.arena_head = None
        return new_pos

    def _dump(self, stack_num):
        assert 0 <= stack_num < self.stack_count
        curr = self.stack_top[stack_num]
        while curr is not None:
            d = self.arena[curr]
            print '\t', curr, d
            curr = d['prev']

    def _dump_all(self):
        print '-' * 30
        for i in range(self.stack_count):
            print "Stack %d" % i
            self._dump(i)

    def _dump_arena(self):
        print "Dump arena"
        curr = self.arena_head
        while curr is not None:
            d = self.arena[curr]
            print '\t', d
            curr = d['next']

    def push(self, stack_num, value):
        assert 0 <= stack_num < self.stack_count
        # Find space in arena for new value, update pointers
        new_pos = self._allocate()
        # Put value-to-push into a stack element
        d = {'value': value, 'prev': self.stack_top[stack_num], 'pos': new_pos}
        self.arena[new_pos] = d
        self.stack_top[stack_num] = new_pos

    def pop(self, stack_num):
        assert 0 <= stack_num < self.stack_count
        top = self.stack_top[stack_num]
        d = self.arena[top]
        assert d['pos'] == top
        self.stack_top[stack_num] = d['prev']
        arena_elem = {'prev': None, 'next': self.arena_head}
        # Link the current head to the new head
        head = self.arena[self.arena_head]
        head['prev'] = top
        # Set the curr_pos to be the new head
        self.arena[top] = arena_elem
        self.arena_head = top
        return d['value']

if __name__ == '__main__':
    sc = StackContainer(3, 10)
    sc._dump_arena()
    sc.push(0, 'First')
    sc._dump_all()
    sc.push(0, 'Second')
    sc.push(0, 'Third')
    sc._dump_all()
    sc.push(1, 'Fourth')
    sc._dump_all()
    print sc.pop(0)
    sc._dump_all()
    print sc.pop(1)
    sc._dump_all()

答案 3 :(得分:5)

为简单起见,如果不是非常有效的内存使用,你可以[*]将数组划分为列表节点,将它们全部添加到空闲节点列表中,然后将堆栈实现为链表,从空闲列表中获取节点按要求。但是,这种方法中的数字3并没有什么特别之处。

[*]是一种低级语言,其中内存可用于存储指针,或者堆栈元素的类型如int可以表示数组的索引。

答案 4 :(得分:5)

我有一个解决这个问题的方法。以下程序充分利用了数组(在我的例子中,是一个StackNode对象数组)。如果你们对此有任何疑问,请告诉我。 [这里已经很晚了,所以我没有费心去记录代码 - 我知道,我应该:)]

public class StackNode {
    int value;
    int prev;

    StackNode(int value, int prev) {
        this.value = value;
        this.prev = prev;
    }
}


public class StackMFromArray {
    private StackNode[] stackNodes = null;
    private static int CAPACITY = 10;
    private int freeListTop = 0;
    private int size = 0;
    private int[] stackPointers = { -1, -1, -1 };

    StackMFromArray() {
        stackNodes = new StackNode[CAPACITY];
        initFreeList();
    }

    private void initFreeList() {
        for (int i = 0; i < CAPACITY; i++) {
            stackNodes[i] = new StackNode(0, i + 1);
        }
    }

    public void push(int stackNum, int value) throws Exception {
        int freeIndex;
        int currentStackTop = stackPointers[stackNum - 1];
        freeIndex = getFreeNodeIndex();
        StackNode n = stackNodes[freeIndex];
        n.prev = currentStackTop;
        n.value = value;
        stackPointers[stackNum - 1] = freeIndex;
    }

    public StackNode pop(int stackNum) throws Exception {
        int currentStackTop = stackPointers[stackNum - 1];
        if (currentStackTop == -1) {
            throw new Exception("UNDERFLOW");
        }

        StackNode temp = stackNodes[currentStackTop];
        stackPointers[stackNum - 1] = temp.prev;
        freeStackNode(currentStackTop);
        return temp;
    }

    private int getFreeNodeIndex() throws Exception {
        int temp = freeListTop;

        if (size >= CAPACITY)
            throw new Exception("OVERFLOW");

        freeListTop = stackNodes[temp].prev;
        size++;
        return temp;
    }

    private void freeStackNode(int index) {
        stackNodes[index].prev = freeListTop;
        freeListTop = index;
        size--;
    }

    public static void main(String args[]) {
                    // Test Driver
        StackMFromArray mulStack = new StackMFromArray();
        try {
            mulStack.push(1, 11);
            mulStack.push(1, 12);
            mulStack.push(2, 21);
            mulStack.push(3, 31);
            mulStack.push(3, 32);
            mulStack.push(2, 22);
            mulStack.push(1, 13);
            StackNode node = mulStack.pop(1);
            node = mulStack.pop(1);
            System.out.println(node.value);
            mulStack.push(1, 13);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

答案 5 :(得分:3)

早期答案的变体:堆栈#1从左侧增长,堆栈#2从右侧增长。

堆栈#3位于中心,但元素以左右交替的顺序增长。如果N是中心索引,则堆栈增长为:N,N-1,N + 1,N-2,N + 2等。简单函数将堆栈索引转换为数组索引。

答案 6 :(得分:2)

我认为你应该将数组分成3个部分,使第一个堆叠的头部为0,第二个堆叠的头部为n / 3,第三个堆叠的头部为n-1。

所以实现推送操作:

  1. first&amp;第二个堆栈使i ++和第三个堆栈生成i - ;
  2. 如果遇到第一个堆叠没有空间推动,则向前移动第二个堆叠k / 3个位置。其中k是阵列中剩余的位置数。
  3. 如果遇到第二个堆叠没有空间推动,则向后移动第二个堆叠2 * k / 3个位置。其中k是阵列中剩余的位置数。
  4. 如果遇到第三个堆叠没有空间推动,则向后移动第二个堆叠2 * k / 3个位置。其中k是阵列中剩余的位置数。
  5. 当没有剩余空间时,我们正在移动k / 3和2 * k / 3,这样在中间堆栈移位后,每个堆栈都有相同的空间可供使用。

答案 7 :(得分:2)

将数组分为3个部分并不是一个好主意,因为如果stack1中有很多元素,而其他两个元素中只有很少的元素,则会导致溢出。

我的想法:

保留三个指针ptr1ptr2ptr3,以指向各个堆栈的顶部元素。

最初为ptr1 = ptr2 = ptr3 = -1;

在数组中,偶数索引元素将存储值,而奇数索引元素将存储该stack的前一个元素的索引。

例如,

s1.push(1);
s2.push(4);
s3.push(3);
s1.push(2);
s3.push(7);
s1.push(10);
s1.push(5);

然后我们的数组如下:

1, -1, 4, -1, 3, -1, 2, 0, 7, 4, 10, 6, 5, 10

,指针的值是:

ptr1 = 12, ptr2 = 2 , ptr3 = 8

答案 8 :(得分:2)

当第一个堆栈进入索引0,然后0 + 3 = 3,然后3 + 3 = 6 ......时,以这种方式将堆栈存储在该区域中;第二个进入索引1,1 + 3 = 4,4 + 3 = 7 ......;第三个进入索引2,2 + 3 = 5,5 + 3 = 8 因此,如果我们用a标记第一个堆栈元素,用b标记,那么我们得到: a1 b1 c1 a2 b2 c2 a3 b3 c3 ...

可能存在差距,但我们总是知道存储在3元素topIndex数组中的顶级索引。

答案 9 :(得分:1)

<块引用>

这是一个非常常见的面试问题“使用单个 Array 或 >List 实现 3 个堆栈”。 这是我的解决方案-

方法 1- 对数组进行固定除法意味着如果我们将数组分成 3 个相等的部分并推送数组的元素 分成三个固定大小的堆栈。 对于堆栈 1,使用 [0,n/3] 对于堆栈 2,使用 [n/3,2n/3] 对于堆栈 3,使用 [2n/3,n]。这种方法的问题在于,我们可能会面临这样一种情况,即数组的大小可能是 大于堆栈的大小,即。堆栈溢出条件。所以, 我们必须处理这样的特殊情况和边缘情况。现在,走吧 第二种方法。

方法 2- 灵活划分,在第一种方法中,我们面临的情况是数组的大小可能大于数组的大小 堆栈,即堆栈溢出条件。我们可以克服这个 通过对堆栈进行灵活划分来解决问题。添加时 元素到堆栈,当一个堆栈超过初始容量时, 将元素移到下一个堆栈。所以,这样我们就可以接近 这个问题。

答案 10 :(得分:1)

Dr. belisarius's answer解释了基本算法,但没有详细介绍,而且众所周知,魔鬼总是存在于细节中。我用Python 3编写了一个解决方案,并提供了一些说明和单元测试。所有操作都按固定时间运行,就像它们应该对堆栈一样。

# One obvious solution is given array size n, divide up n into 3 parts, and allocate floor(n / 3) cells
# to two stacks at either end of the array, and remaining cells to the one in the middle. This strategy is not
# space efficient because even though there may be space in the array, one of the stack may overflow.
#
# A better approach is to have two stacks at either end of the array, the left one growing on the right, and the
# right one growing on the left. The middle one starts at index floor(n / 2), and grows at both ends. When the
# middle stack size is even, it grows on the right, and when it's odd, it grows on the left. This way, the middle
# stack grows evenly and minimizes the changes of overflowing one of the stack at either end.
#
# The rest is pointer arithmetic, adjusting tops of the stacks on push and pop operations.

class ThreeStacks:
    def __init__(self, n: int):
        self._arr: List[int] = [0] * n
        self._tops: List[int] = [-1, n, n // 2]
        self._sizes: List[int] = [0] * 3
        self._n = n

    def _is_stack_3_even_size(self):
        return self._sizes[2] % 2 == 0

    def _is_stack_3_odd_size(self):
        return not self._is_stack_3_even_size()

    def is_empty(self, stack_number: int) -> bool:
        return self._sizes[stack_number] == 0

    def is_full(self, stack_number: int) -> bool:
        if stack_number == 0 and self._is_stack_3_odd_size():
            return self._tops[stack_number] == self._tops[2] - self._sizes[2]
        elif stack_number == 1 and self._is_stack_3_even_size():
            return self._tops[stack_number] == self._tops[2] + self._sizes[2]

        return (self._is_stack_3_odd_size() and self._tops[0] == self._tops[2] - self._sizes[2]) or \
               (self._is_stack_3_even_size() and self._tops[1] == self._tops[2] + self._sizes[2])

    def pop(self, stack_number: int) -> int:
        if self.is_empty(stack_number):
            raise RuntimeError(f"Stack : {stack_number} is empty")

        x: int = self._arr[self._tops[stack_number]]
        if stack_number == 0:
            self._tops[stack_number] -= 1
        elif stack_number == 1:
            self._tops[stack_number] += 1
        else:
            if self._is_stack_3_even_size():
                self._tops[stack_number] += (self._sizes[stack_number] - 1)
            else:
                self._tops[stack_number] -= (self._sizes[stack_number] - 1)

        self._sizes[stack_number] -= 1
        return x

    def push(self, item: int, stack_number: int) -> None:
        if self.is_full(stack_number):
            raise RuntimeError(f"Stack: {stack_number} is full")

        if stack_number == 0:
            self._tops[stack_number] += 1
        elif stack_number == 1:
            self._tops[stack_number] -= 1
        else:
            if self._is_stack_3_even_size():
                self._tops[stack_number] += self._sizes[stack_number]
            else:
                self._tops[stack_number] -= self._sizes[stack_number]
        self._arr[self._tops[stack_number]] = item
        self._sizes[stack_number] += 1

    def __repr__(self):
        return str(self._arr)

测试:

def test_stack(self):
    stack = ThreeStacks(10)

    for i in range(3):
        with pytest.raises(RuntimeError):
            stack.pop(i)

    for i in range(1, 4):
        stack.push(i, 0)

    for i in range(4, 7):
        stack.push(i, 1)

    for i in range(7, 11):
        stack.push(i, 2)

    for i in range(3):
        with pytest.raises(RuntimeError):
            stack.push(1, i)

    assert [stack.pop(i) for i in range(3)] == [3, 6, 10]
    assert [stack.pop(i) for i in range(3)] == [2, 5, 9]
    assert [stack.pop(i) for i in range(3)] == [1, 4, 8]

    for i in range(2):
        assert stack.is_empty(i)

    assert not stack.is_empty(2)
    assert stack.pop(2) == 7
    assert stack.is_empty(2)

答案 11 :(得分:1)

我们可以将其概括为一个数组中的K个堆栈。基本思路是:

  
      
  • 将PriorityQueue保持为分配数组中当前可用索引的最小堆。
  •   
  • 为每个堆栈维护一个大小为K的数组,该数组占据堆栈的顶部。
  •   
  • 使用1)值2)分配数组中Prev元素的索引创建一个Data类3)将当前元素的索引推入   分配数组
  •   
  • 维护类型为Data的分配数组
  •   

请参阅代码以获取有效的示例实现。

import java.util.*;
public class Main 
{ 
    // A Java class to represent k stacks in a single array of size n 
    public static final class KStack {

      /**
      * PriorityQueue as min heap to keep track of the next free index in the 
      * backing array.
      */
      private final PriorityQueue<Integer> minHeap = new PriorityQueue<>((a,b) -> (a - b));

      /**
      * Keeps track of the top of the stack of each of the K stacks
      */
      private final Data index[];

      /**
      * Backing array to hold the data of K stacks.
      */
      private final Data array[];

      public KStack(int noOfStacks, int sizeOfBackingArray) {
        index = new Data[noOfStacks];
        array = new Data[sizeOfBackingArray];

        for(int i =0; i< sizeOfBackingArray; i++) {
          minHeap.add(i);
        }
      }


      public void push(int val, int stackNo) {
        if(minHeap.isEmpty()) {
          return;
        }

        int nextFreeIdx = minHeap.poll();
        Data tos = index[stackNo];
        if(tos == null) {
          tos = new Data(val, -1 /* Previous elemnet's idx*/, nextFreeIdx
                        /* This elemnent's idx in underlying array*/);
        } else {
          tos = new Data(val, tos.myIndex, nextFreeIdx);
        }

        index[stackNo] = tos;
        array[nextFreeIdx] = tos;
      }

      public int pop(int stackNo) {
        if(minHeap.size() == array.length) {
          return -1; // Maybe throw Exception?
        }

        Data tos = index[stackNo];
        if(tos == null) {
          return -1; // Maybe throw Exception?
        }

        minHeap.add(tos.myIndex);
        array[tos.myIndex] = null;

        int value = tos.value;
        if(tos.prevIndex == -1) {
          tos = null;
        } else {
          tos = array[tos.prevIndex];
        }

        index[stackNo] = tos;
        return value;
      }
    }

   public static final class Data {
     int value;
     int prevIndex;
     int myIndex;

     public Data(int value, int prevIndex, int myIndex) {
       this.value = value;
       this.prevIndex = prevIndex;
       this.myIndex = myIndex;
     }

     @Override
     public String toString() {
       return "Value: " + this.value + ", prev: " + this.prevIndex + ", myIndex: " + myIndex; 
     }
   }

    // Driver program 
    public static void main(String[] args) 
    { 
        int noOfStacks = 3, sizeOfBackingArray = 10; 

        KStack ks = new KStack(noOfStacks, sizeOfBackingArray); 

        // Add elements to stack number 1
        ks.push(11, 0); 
        ks.push(9, 0); 
        ks.push(7, 0); 

    // Add elements to stack number 3
        ks.push(51, 2); 
        ks.push(54, 2); 

        // Add elements to stack number 2
        ks.push(71, 1); 
        ks.push(94, 1); 
        ks.push(93, 1); 


        System.out.println("Popped from stack 3: " + ks.pop(2)); 
        System.out.println("Popped from stack 3: " + ks.pop(2)); 
        System.out.println("Popped from stack 3: " + ks.pop(2)); 
        System.out.println("Popped from stack 2: " + ks.pop(1)); 
        System.out.println("Popped from stack 1: " + ks.pop(0)); 
    } 
} 

答案 12 :(得分:1)

这是我在单个阵列中N个堆栈的解决方案。

一些约束将在这里。 该数组的大小将不小于堆栈数。

我曾经在解决方案中自定义异常类StackException。您可以更改用于运行程序的异常类。

对于数组中的多个堆栈,我管理了指向另一个数组的指针。

package com.practice.ds.stack;

import java.util.Scanner;
import java.util.logging.Logger;

/** Multiple stacks in a single array */
public class MultipleStack {

    private static Logger logger = Logger.getLogger("MultipleStack");

    private int[] array;
    private int size = 10;
    private int stackN = 1;
    private int[] pointer;

    public MultipleStack() {
        this.array = new int[size];
        this.pointer = new int[1];
    }

    public MultipleStack(int size, int stackN) throws StackException {
        if (stackN > size)
            throw new StackException("Input mismatch ! no of stacks can't be larger than size ");
        this.size = size;
        this.stackN = stackN;
        init();
    }

    private void init() {
        if (size <= 0) {
            logger.info("Initialize size is " + size + " so assiginig defalt size ");
            this.size = 10;
        }
        if (stackN < 1) {
            logger.info("Initialize no of Stack is " + size + " so assiginig defalt");
            this.stackN = 1;
        }
        this.array = new int[size];
        this.pointer = new int[stackN];
        initializePointer();
    }

    private void initializePointer() {
        for (int i = 0; i < stackN; i++)
            pointer[i] = (int)(i * Math.ceil(size / stackN) - 1);
    }

    public void push(int item, int sn) throws StackException {
        if (full(sn))
            throw new StackException(sn + " is overflowed !");
        int stkPointer = pointer[sn - 1];
        array[++stkPointer] = item;
        pointer[sn - 1] = stkPointer;
    }

    public void pop(int sn) throws StackException {
        if (empty(sn))
            throw new StackException(sn + " is underflow !");
        int peek = peek(sn);
        System.out.println(peek);
        pointer[sn - 1] = --pointer[sn - 1];
    }

    public int peek(int sn) throws StackException {
        authenticate(sn);
        return array[pointer[sn - 1]];
    }

    public boolean empty(int sn) throws StackException {
        authenticate(sn);
        return pointer[sn - 1] == (int)(((sn - 1) * Math.ceil(size / stackN)) - 1);
    }

    public boolean full(int sn) throws StackException {
        authenticate(sn);
        return sn == stackN ? pointer[sn - 1] == size - 1 :  pointer[sn - 1] == (int)((sn) * Math.ceil(size / stackN)) - 1;
    }

    private void authenticate(int sn) throws StackException {
        if (sn > stackN || sn < 1)
            throw new StackException("No such stack found");
    }

    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.println("Define size of the stack");
            int size = scanner.nextInt();
            System.out.println("total number of stacks");
            int stackN = scanner.nextInt();
            MultipleStack stack = new MultipleStack(size, stackN);
            boolean exit = false;
            do {
                System.out.println("1. Push");
                System.out.println("2. Pop");
                System.out.println("3. Exit");
                System.out.println("Choice");
                int choice = scanner.nextInt();
                switch (choice) {
                case 1:
                    try {
                        System.out.println("Item : ");
                        int item = scanner.nextInt();
                        System.out.println("Stack Number : ");
                        int stk = scanner.nextInt();
                        stack.push(item, stk);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;

                case 2:
                    try {
                        System.out.println("Stack Number : ");
                        int stk = scanner.nextInt();
                        stack.pop(stk);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;

                case 3:
                    exit = true;
                    break;

                default:
                    System.out.println("Invalid choice !");
                    break;
                }
            } while (!exit);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

答案 13 :(得分:1)

解决方案:实现两个堆栈非常简单。 第一个堆栈从头到尾增长,而第二个堆栈从头到尾增长。 除非阵列上没有剩余空间,否则不会发生任何溢出。

对于三个堆栈,需要以下内容: 一个辅助数组,用于维护每个节点的父节点。 用于存储每个堆栈当前顶部的变量。 有了这两个,所有堆栈中的数据可以散布在原始数组中,并且仍然可以对所有堆栈执行push / pop / size操作。

enter image description here

插入任何元素时,将其插入普通数组中所有元素的末尾。 将该堆栈的当前顶部存储为新元素的父级(在父级&#39;数组中),并将current-top更新为新位置。

删除时,在stacks数组中为deleted元素插入NULL,并将该堆栈的stack-top重置为父元素。

当数组已满时,它将有一些对应于已删除元素的孔。 此时,可以压缩阵列以将所有可用空间组合在一起,或者在插入新元素时可以对可用空间进行线性搜索。

有关详细信息,请参阅此链接: - https://coderworld109.blogspot.in/2017/12/how-to-implement-3-stacks-with-one-array.html

答案 14 :(得分:1)

此页面上已说明此问题的解决方案有很多种。恕我直言的基本问题是:

  • 每次推/弹操作需要多长时间?

  • 使用了多少空间?具体来说,可以推送到三个堆栈以使数据结构空间不足的最小元素数是多少?

据我所知,已经发布在此页面上的每个解决方案都可能占用推送/弹出的线性时间,或者空间不足,线性数量的空格仍为空。

在这篇文章中,我将介绍性能更好的解决方案,我将介绍最简单的解决方案。

为了更仔细地描述解空间,我将通过以下方式引用数据结构的两个函数:

采用O(f(n))摊销时间执行推/弹并且不会耗尽空间的结构,除非三个堆栈至少保存n - O(g(n))项目将被引用作为(f,g)结构。较小的f和g更好。已发布在此页面上的每个结构都有n个时间或空格。我将展示一个(1,√n)结构。

这完全基于:

  • Michael L. Fredman和Deborah L. Goldsmith,“Three Stacks”,“Journal of Algorithms”,第17卷,第1期,1994年7月,第45-70页

    • 早期版本出现在1988年第29届计算机科学基础年会(FOCS)研讨会上
  • Deborah Louise Goldsmith博士论文来自加利福尼亚大学圣地亚哥分校电子工程/计算机科学系1987年,“高效的内存管理&gt; = 3堆栈”

他们表示,虽然我不会出现任何S的(log n / log S,S)结构。这相当于任何一个(t,n 1 / t )结构吨。我将展示一个(1,√n)结构的简化版本。

将数组划分为大小为Θ(√n)的块。块的编号从1到Θ(√n),块的编号称为“地址”。地址可以存储在数组槽中而不是实际项目中。给定块内的项目可以用小于O(√n)的数字来引用,并且这样的数字称为索引。索引也适合数组插槽。

第一个块将被留出来存储地址和索引,没有其他块可以存储任何地址或索引。第一个块称为目录。每个非目录块都将为空或仅保存三个堆栈中的一个;也就是说,没有块将具有来自不同堆栈的两个元素。此外,每个堆栈最多只有一个部分填充的块 - 与堆栈关联的所有其他块将完全填满或完全为空。

只要存在空块,就可以对任何堆栈执行推送操作。始终允许弹出操作。当推送操作失败时,数据结构已满。此时,不包含其中一个堆栈的元素的槽数最多为O(√n):堆栈中两个部分填充的块未被推送到,以及一个目录块。

每个块都是有序的,这样靠近块前面的元素(较低的索引)更靠近堆栈的底部。

目录成立:

  • 三个堆栈顶部块的三个地址,如果特定堆栈中没有块,则为0

  • 三个堆栈顶部元素的三个索引,如果特定堆栈中没有项目,则为0。

  • 对于每个完整或部分完整的块,块的地址低于同一堆栈中的块,如果它是堆栈中的最低块,则为0。

  • 空闲块的地址,称为前导块,如果没有空闲块,则为0

  • 对于每个空闲块,另一个空闲块的地址,如果没有更多空闲块,则为0

最后两个构成一个堆栈,存储为单链表,包含空闲块。也就是说,遵循以引导块开头的空闲块的地址将给出通过所有空闲块的路径,以0结尾。

要将项目推送到堆栈,请使用该目录在该块中找到其顶部块和顶部元素。如果该区块中有空间,请将该项目放在那里并返回。

否则,通过将引导块的地址更改为空闲块堆栈中下一个空闲块的地址来弹出空闲块堆栈。将堆栈的地址和索引分别更改为刚刚弹出的空闲块的地址和1。将项添加到索引1处的刚刚弹出的块中,然后返回。

所有操作都需要O(1)时间。流行是对称的。

答案 15 :(得分:0)

这是我在C#中的解决方案 -

/*  Program: Implement 3 stacks using a single array
 *
 *  Date: 12/26/2015
 */

using System;

namespace CrackingTheCodingInterview
{
    internal class Item
    {
        public object data;
        public int prev;
    }

    /// <summary>
    /// Class implementing 3 stacks using single array
    /// </summary>
    public class Stacks
    {
        /// <summary>
        /// Pushing an element 'data' onto a stack 'i'
        /// </summary>
        public void Push(int i, object d)
        {
            i--;
            if (available != null)
            {
                int ava = (int)available.DeleteHead();
                elems[ava].data = d;
                elems[ava].prev = top[i];
                top[i] = ava;
            }
            else
            {
                Console.WriteLine("Array full. No more space to enter!");
                return;
            }
        }

        /// <summary>
        /// Popping an element from stack 'i'
        /// </summary>
        public object Pop(int i)
        {
            i--;
            if (top[i] != -1)
            {
                object popVal = elems[top[i]].data;
                int prevTop = elems[top[i]].prev;
                elems[top[i]].data = null;
                elems[top[i]].prev = -1;
                available.Insert(top[i]);
                top[i] = prevTop;

                return popVal;
            }
            else
            {
                Console.WriteLine("Stack: {0} empty!", i);
                return null;
            }
        }

        /// <summary>
        /// Peeking top element of a stack
        /// </summary>
        public object Peek(int i)
        {
            i--;
            if (top[i] != -1)
            {
                return elems[top[i]].data;
            }
            else
            {
                Console.WriteLine("Stack: {0} empty!", i);
                return null;
            }
        }

        /// <summary>
        /// Constructor initializing array of Nodes of size 'n' and the ability to store 'k' stacks
        /// </summary>
        public Stacks(int n, int k)
        {
            elems = new Item[n];
            top = new int[k];

            for (int i = 0; i < k; i++)
            {
                top[i] = -1;
            }

            for (int i = 0; i < n; i++)
            {
                elems[i] = new Item();
                elems[i].data = null;
                elems[i].prev = -1;
            }

            available = new SinglyLinkedList();

            for (int i = n - 1; i >= 0; i--)
            {
                available.Insert(i);
            }
        }

        private Item[] elems;
        private int[] top;
        private SinglyLinkedList available;
    }

    internal class StacksArrayTest
    {
        static void Main()
        {
            Stacks s = new Stacks(10, 3);
            s.Push(1, 'a');
            s.Push(1, 'b');
            s.Push(1, 'c');

            Console.WriteLine("After pushing in stack 1");
            Console.WriteLine("Top 1: {0}", s.Peek(1));

            s.Push(2, 'd');
            s.Push(2, 'e');
            s.Push(2, 'f');
            s.Push(2, 'g');

            Console.WriteLine("After pushing in stack 2");
            Console.WriteLine("Top 1: {0}", s.Peek(1));
            Console.WriteLine("Top 2: {0}", s.Peek(2));

            s.Pop(1);
            s.Pop(2);

            Console.WriteLine("After popping from stack 1 and 2");
            Console.WriteLine("Top 1: {0}", s.Peek(1));
            Console.WriteLine("Top 2: {0}", s.Peek(2));

            s.Push(3, 'h');
            s.Push(3, 'i');
            s.Push(3, 'j');
            s.Push(3, 'k');
            s.Push(3, 'l');

            Console.WriteLine("After pushing in stack 3");
            Console.WriteLine("Top 3: {0}", s.Peek(3));

            Console.ReadLine();
        }
    }
}

输出:

After pushing in stack 1
Top 1: c
After pushing in stack 2
Top 1: c
Top 2: g
After popping from stack 1 and 2
Top 1: b
Top 2: f
After pushing in stack 3
Top 3: l

我参考这篇文章对其进行编码 - http://codercareer.blogspot.com/2013/02/no-39-stacks-sharing-array.html

答案 16 :(得分:0)

的Python

class Stack:

    def __init__(self):
        self.pos_1 = 0
        self.pos_2 = 1
        self.pos_3 = 2
        self.stack = [None, None, None]

    def pop_1(self):
        if self.pos_2 - 1 > 0:
            to_ret = self.stack.pop(self.pos_1)
            self.pos_2 -= 1
            self.pos_3 -= 1
        return to_ret

    def push_1(self, value):
        self.stack.insert(self.pos_1, value)
        self.pos_2 += 1
        self.pos_3 += 1
        return None

    def pop_2(self):
        if self.pos_2 - 1 < self.pos_3:
            to_ret = self.stack.pop(self.pos_2)
            self.pos_3 -= 1
        return to_ret

    def push_2(self, value):
        self.stack.insert(self.pos_2, value)
        self.pos_3 += 1
        return None

    def pop_3(self):
        if self.pos_3 - 1 > self.pos_2:
            to_ret = self.stack.pop(self.pos_3)
        return to_ret

    def push_3(self, value):
        self.stack.insert(self.pos_3, value)
        return None

if __name__ == "__main__":
    stack = Stack()
    stack.push_2(22)
    stack.push_1(1)
    stack.push_1(2)
    print stack.pop_1()
    print stack.pop_1()
    print stack.pop_2()

打印: 2 1 22

答案 17 :(得分:-1)

enum stackId{LEFT, MID, RIGHT };

class threeStacks {

int* arr;

int leftSize;
int rightSize;
int midSize;
int mid;
int maxSize;
public:
    threeStacks(int n):leftSize(0), rightSize(0), midSize(0), mid(n/2), maxSize(n)
    {
        arr = new int[n];
    }

    void push(stackId sid, int val){
        switch(sid){
            case LEFT:
                pushLeft(val);
            break;

            case MID:
                pushMid(val);
            break;

            case RIGHT:
                pushRight(val);
        }
    }

    int pop(stackId sid){
        switch(sid){
            case LEFT:
                return popLeft();
            case MID:
                return popMid();
            case RIGHT:
                return popRight();
        }
    }


    int top(stackId sid){
        switch(sid){
            case LEFT:
                return topLeft();
            case MID:
                return topMid();
            case RIGHT:
                return topRight();
        }
    }

    void pushMid(int val){
        if(midSize+leftSize+rightSize+1 > maxSize){
            cout << "Overflow!!"<<endl;
            return;
        }
        if(midSize % 2 == 0){
            if(mid - ((midSize+1)/2) == leftSize-1){
                //left side OverFlow
                if(!shiftMid(RIGHT)){
                    cout << "Overflow!!"<<endl;
                    return; 
                }
            }
            midSize++;
            arr[mid - (midSize/2)] = val;
        }
        else{
            if(mid + ((midSize+1)/2) == (maxSize - rightSize)){
                //right side OverFlow
                if(!shiftMid(LEFT)){
                    cout << "Overflow!!"<<endl;
                    return; 
                }
            }
            midSize++;
            arr[mid + (midSize/2)] = val;                           
        }
    }

    int popMid(){
        if(midSize == 0){
            cout << "Mid Stack Underflow!!"<<endl;
            return -1;
        }
        int val;
        if(midSize % 2 == 0)
            val = arr[mid - (midSize/2)];
        else
            val = arr[mid + (midSize/2)];
        midSize--;
        return val;
    }

    int topMid(){
        if(midSize == 0){
            cout << "Mid Stack Underflow!!"<<endl;
            return -1;
        }
        int val;
        if(midSize % 2 == 0)
            val = arr[mid - (midSize/2)];
        else
            val = arr[mid + (midSize/2)];
        return val;
    }

    bool shiftMid(stackId dir){
        int freeSpace;
        switch (dir){
            case LEFT:
                freeSpace = (mid - midSize/2) - leftSize;
                if(freeSpace < 1)
                    return false;               
                if(freeSpace > 1)
                    freeSpace /= 2;
                for(int i=0; i< midSize; i++){
                    arr[(mid - midSize/2) - freeSpace + i] = arr[(mid - midSize/2) + i];
                }
                mid = mid-freeSpace;
            break;
            case RIGHT:
                freeSpace = maxSize - rightSize - (mid + midSize/2) - 1;
                if(freeSpace < 1)
                    return false;               
                if(freeSpace > 1)
                    freeSpace /= 2;
                for(int i=0; i< midSize; i++){
                    arr[(mid + midSize/2) + freeSpace - i] = arr[(mid + midSize/2) - i];
                }
                mid = mid+freeSpace;
            break;              
            default:
                return false;
        }
    }

    void pushLeft(int val){
        if(midSize+leftSize+rightSize+1 > maxSize){
            cout << "Overflow!!"<<endl;
            return;
        }
        if(leftSize == (mid - midSize/2)){
            //left side OverFlow
            if(!shiftMid(RIGHT)){
                cout << "Overflow!!"<<endl;
                return; 
            }
        }
        arr[leftSize] = val;
        leftSize++;
    }

    int popLeft(){
        if(leftSize == 0){
            cout << "Left Stack Underflow!!"<<endl;
            return -1;
        }
        leftSize--;
        return arr[leftSize];
    }

    int topLeft(){
        if(leftSize == 0){
            cout << "Left Stack Underflow!!"<<endl;
            return -1;
        }
        return arr[leftSize - 1];
    }

    void pushRight(int val){
        if(midSize+leftSize+rightSize+1 > maxSize){
            cout << "Overflow!!"<<endl;
            return;
        }
        if(maxSize - rightSize - 1 == (mid + midSize/2)){
            //right side OverFlow
            if(!shiftMid(LEFT)){
                cout << "Overflow!!"<<endl;
                return; 
            }
        }
        rightSize++;
        arr[maxSize - rightSize] = val;
    }

    int popRight(){
        if(rightSize == 0){
            cout << "Right Stack Underflow!!"<<endl;
            return -1;
        }
        int val = arr[maxSize - rightSize];
        rightSize--;
        return val;
    }

    int topRight(){
        if(rightSize == 0){
            cout << "Right Stack Underflow!!"<<endl;
            return -1;
        }
        return arr[maxSize - rightSize];
    }

};

答案 18 :(得分:-1)

包job.interview; import java.util.Arrays;

public class NStack1ArrayGen<T> {

    T storage[];
    int numOfStacks;
    Integer top[];
    public NStack1ArrayGen(int numOfStks, T myStorage[]){
        storage = myStorage;
        numOfStacks = numOfStks;
        top = new Integer[numOfStks];
        for(int i=0;i<numOfStks;i++){top[i]=-1;}
    }
    public void push(int stk_indx, T value){
        int r_indx = stk_indx -1;
        if(top[r_indx]+numOfStacks < storage.length){
            top[r_indx] = top[r_indx] < 0 ? stk_indx-1 : top[r_indx]+numOfStacks;
            storage[top[r_indx]] = value;
        }
    }
    public T pop(int stk_indx){
        T ret = top[stk_indx-1]<0 ? null : storage[top[stk_indx-1]];
        top[stk_indx-1] -= numOfStacks;
        return ret;
    }
    public void printInfo(){
        print("The array", Arrays.toString(storage));
        print("The top indices", Arrays.toString(top));
        for(int j=1;j<=numOfStacks;j++){
            printStack(j);
        }
    }
    public void print(String name, String value){
        System.out.println(name + " ==> " + value);
    }
    public void printStack(int indx){
        String str = "";
        while(top[indx-1]>=0){
            str+=(str.length()>0 ? "," : "") + pop(indx);
        }
        print("Stack#"+indx,str);
    }
    public static void main (String args[])throws Exception{
        int count=4, tsize=40;
        int size[]={105,108,310,105};
        NStack1ArrayGen<String> mystack = new NStack1ArrayGen<String>(count,new String[tsize]); 
        for(int i=1;i<=count;i++){
            for(int j=1;j<=size[i-1];j++){
                mystack.push(i, "stk"+i+"_value"+j);
            }
        }
    }
}

打印:

  

数组==&gt; [stk1_value1,stk2_value1,stk3_value1,stk4_value1,stk1_value2,stk2_value2,stk3_value2,stk4_value2,stk1_value3,stk2_value3,stk3_value3,stk4_value3,stk1_value4,stk2_value4,stk3_value4,stk4_value4,stk1_value5,stk2_value5,stk3_value5,stk4_value5,stk1_value6,stk2_value6,stk3_value6,stk4_value6,stk1_value7 ,stk2_value7,stk3_value7,stk4_value7,stk1_value8,stk2_value8,stk3_value8,stk4_value8,stk1_value9,stk2_value9,stk3_value9,stk4_value9,stk1_value10,stk2_value10,stk3_value10,stk4_value10]   最高指数==&gt; [36,37,38,39]   堆栈#1 ==&gt; stk1_value10,stk1_value9,stk1_value8,stk1_value7,stk1_value6,stk1_value5,stk1_value4,stk1_value3,stk1_value2,stk1_value1   堆栈#2 ==&gt; stk2_value10,stk2_value9,stk2_value8,stk2_value7,stk2_value6,stk2_value5,stk2_value4,stk2_value3,stk2_value2,stk2_value1   堆栈#3 ==&gt; stk3_value10,stk3_value9,stk3_value8,stk3_value7,stk3_value6,stk3_value5,stk3_value4,stk3_value3,stk3_value2,stk3_value1   堆栈#4 ==&gt; stk4_value10,stk4_value9,stk4_value8,stk4_value7,stk4_value6,stk4_value5,stk4_value4,stk4_value3,stk4_value2,stk4_value1