数据结构(栈和队列)

题目一:栈的压入和弹出顺序

  • 题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的数字均不相等。例如序列1,2,3,4,5是某栈的压栈序列,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
  • 思路:用两个数组来表示两个序列,用两个index来指向各自数组当前的引用,用一个栈来记录压栈的过程,stack 压入数字1, 比较1与另一个序列当前的值即4,发现不等,继续压栈,直到原始序列中4被压入,此时弹出4,另一个序列的index向后移动一位,再继续比较,直到第一个序列指针指向最后一位,而stack也空了,则该序列是压栈序列的弹出序列,如果指针指向了最后一个数字,但是stack里任然有值,则不是。
    static bool IsPopOrder(int[] order, int[] popOrder)
        {
            Stack<int> stack = new Stack<int>();
            int currentOrderIndex = 0;     // 原始序列当前指针
            int currentPopOrderIndex = 0;  //待检验序列当前指针

            if (order == null || popOrder == null || order.Length != popOrder.Length || order.Length == 0)
            {
                return false; //鲁棒性考虑
            }
            if (order.Length == 1 && order[0] == popOrder[0])
            {
                return true;//如果各自序列都只有一个值,而且相等,则OK
            }
            stack.Push(order[currentOrderIndex]); //将原始序列第一个值压栈
            currentOrderIndex++; //指针指向后一位。
            while (currentOrderIndex <= order.Length) //原始序列的当前指针没有指向最后则一直循环  
//加等号是为了让循环继续,因为最后被加入stack里的值,还没有机会pop出来
{ while (stack.Count > 0 && stack.Peek() == popOrder[currentPopOrderIndex])//如果栈顶的数字和待检验的序列当前数字相等 { stack.Pop();//弹出 currentPopOrderIndex++;//待检验序列当前指针向后移。 } //如果不相等,则 if (currentOrderIndex < order.Length) { stack.Push(order[currentOrderIndex]);//原始序列压栈 } currentOrderIndex++; //原始序列指针向后移动 } if (stack.Count == 0) { return true; } return false; }

 

题目二: 设计包含min函数的栈[数据结构]  

  • 题目:定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。
  • 思路:定义两个栈,一个主栈,一个辅栈,主栈在push的时候,辅栈做check,新push进来的值与当前辅栈栈顶的值比大小,如果比栈顶的值小,则压入栈顶,pop的时候,做check,如果主栈pop出去的值是否和辅栈栈顶的值相等(即最小值)如果相等,则把辅栈栈顶的值也pop掉。
public class WithMinStack
    {
        Stack<int> dataStack;
        Stack<int> minStack;

        public WithMinStack()
        {
            dataStack = new Stack<int>();
            minStack = new Stack<int>();
        }

        public void Push(int value)
        {
            dataStack.Push(value);
            if (minStack.Count == 0 || minStack.Peek() > value)
            {
                minStack.Push(value);
            }
        }

        public int Pop()
        {
            int popValue = dataStack.Pop();
            if (popValue == minStack.Peek())
            {
                minStack.Pop();
            }
            return popValue;
        }

        public int Min()
        {
            return minStack.Peek();
        }
    }

 题目三: 用两个队列实现栈

  • 题目:用两个队列实现栈 
  • 思路:  定义两个队列queue1和queue2, Push的时候,始终往queue1里push, pop的时候看queue1里是不是有值,如果有,则把queue1里除最后一个值以外的值导入到queue2里,pop出最后一个值,如果没有值,则将queue2里的值导入到queue1里,pop出最后一个值。

 

public class CustomStack<T>
    {
        private Queue<T> queue1;
        private Queue<T> queue2;
        public CustomStack()
        {
            queue1 = new Queue<T>();
            queue2 = new Queue<T>();
        }

        public void Push(T value)
        {
            queue1.Enqueue(value);
        }

        public T Pop()
        {
            if (queue1.Count == 0)
            {
                while (queue2.Count > 1)
                {
                    queue1.Enqueue(queue2.Dequeue());
                }
                return queue2.Dequeue();
            }
            else
            {
                while (queue1.Count > 1)
                {
                    queue2.Enqueue(queue1.Dequeue());
                }
                return queue1.Dequeue();
            }
        }
    }

 

 题目四: 用两个栈实现队列

  • 题目:用两个栈实现队列
  • 思路: 

    我们通过一个具体的例子来分析往该队列插入和删除元素的过程。首先插入一个元素a,不妨把先它插入到m_stack1。这个时候m_stack1中的元素有{a},m_stack2为空。再插入两个元素b和c,还是插入到m_stack1中,此时m_stack1中的元素有{a,b,c},m_stack2中仍然是空的。

    这个时候我们试着从队列中删除一个元素。按照队列先入先出的规则,由于a比b、c先插入到队列中,这次被删除的元素应该是a。元素a存储在m_stack1中,但并不在栈顶上,因此不能直接进行删除。注意到m_stack2我们还一直没有使用过,现在是让m_stack2起作用的时候了。如果我们把m_stack1中的元素逐个pop出来并push进入m_stack2,元素在m_stack2中的顺序正好和原来在m_stack1中的顺序相反。因此经过两次pop和push之后,m_stack1为空,而m_stack2中的元素是{c,b,a}。这个时候就可以pop出m_stack2的栈顶a了。pop之后的m_stack1为空,而m_stack2的元素为{c,b},其中b在栈顶。

    这个时候如果我们还想继续删除应该怎么办呢?在剩下的两个元素中b和c,b比c先进入队列,因此b应该先删除。而此时b恰好又在栈顶上,因此可以直接pop出去。这次pop之后,m_stack1中仍然为空,而m_stack2为{c}

    从上面的分析我们可以总结出删除一个元素的步骤:当m_stack2中不为空时,在m_stack2中的栈顶元素是最先进入队列的元素,可以pop出去。如果m_stack2为空时,我们把m_stack1中的元素逐个pop出来并push进入m_stack2。由于先进入队列的元素被压到m_stack1的底端,经过pop和push之后就处于m_stack2的顶端了,又可以直接pop出去。

    接下来我们再插入一个元素d。我们是不是还可以把它push进m_stack1?这样会不会有问题呢?我们说不会有问题。因为在删除元素的时候,如果m_stack2中不为空,处于m_stack2中的栈顶元素是最先进入队列的,可以直接pop;如果m_stack2为空,我们把m_stack1中的元素pop出来并push进入m_stack2。由于m_stack2中元素的顺序和m_stack1相反,最先进入队列的元素还是处于m_stack2的栈顶,仍然可以直接pop。不会出现任何矛盾。

 

public class CustomQueue<T>
    {
        Stack<T> firstStack;
        Stack<T> secondStack;

        public CustomQueue()
        {
            firstStack = new Stack<T>();
            secondStack = new Stack<T>();
        }

        public void Enqueue(T item)
        {
            firstStack.Push(item);
            Count = Count + 1;
        }

        public T Deque()
        {
            if (secondStack.Count == 0)
            {
                while (firstStack.Count > 0)
                {
                    secondStack.Push(firstStack.Pop());
                }

            }
            Count = Count - 1;
            return secondStack.Pop();
        }

        public int Count { get; private set; }
    }

 

posted @ 2015-09-06 12:22  莱茵哈特  阅读(241)  评论(0编辑  收藏  举报