• 一个翻拍过程 翻排使用队列


    本周四同事分享了一个思维训练的PPT,里面有一个关于翻牌的题目,题目大致是:拿出从A到10的10张扑克牌,背面朝上摞在一起。首先把最上面的一张挪到下面,掀开新出现的一张牌是A,取出,再挪一张牌到下面,翻一张是2,依次类推,可以有顺序地翻出A到10的牌来。请问这10张牌最初是怎么排列的?看完这个题目,我当时说可以用一个算法实现。

    第二天6点多醒来就一直在想这个问题,开始的时候想用递归实现,最后发现有点复杂,自己实现不了,然后想用数组实现,想法大致是这样的,先将这N个数存到数组中,然后将第一张插到最后面,第二张为A,以此类推,将每张牌经过的索引都记下来,因为每张牌最后是几是知道的,然后反推出1~N张牌是多少,但是发现记录牌经过的索引有点麻烦,效率也不高,记录的数组的第一个元素即为所求。

    早上到了公司一边干活,一边实现这个算法,从题目可以很容易看出奇数位一次为1~N/2,剩下的就是求偶数位的值,马上写了个算法,运行是发现有的结果是正确的,大部分是错的,于是写了个测试方法,测试方法就很简单了,这个方法只用模拟翻牌的过程,然后输出的结果为1~N就是正确的,否则就是错误的。经测试发现我的算法思路完全是错误的,但是通过这个测试算法,我发现了能够正确实现这个题目的方法。这个题目其实不是一个递归的过程,而是一个进栈出栈的过程,奇数位进栈,偶数位出栈。我们知道最后的结果,把每张牌当做一个对象,就是进栈出栈都是以引用的方式,翻牌完成后,按顺序将它们的值一次赋值为1~N,那么我们也就知道开始的牌的顺序了,就这么简单,思路就这么简单,实现起来也就很快,于是马上实现了一个粗糙算法,最后用一个Window Form实现了,发给了同事看看,为了让大家能看得清楚,记录了翻牌的过程,当然要记录过程也是很简单的。

    代码真的很简单,将每张牌当做一个对象,这样就不用记录牌经过的过程,引用类型吗!创建的对象的个数为N,过程也是线性的,不会有性能问题。

    主要代码如下(代码很粗糙,但思路简单清晰,我们知道就是对的),源码下载

    复制代码
     //将牌定义成对象
            public class Card
            { 
                public int Value=0 ;
                public override string ToString()
                {
                    return Value.ToString();
                } 
            }
    
            //测试算法,记录了翻牌过程
            static List<string> TestResult(Card[] arr)
            {
                if (arr == null)
                { 
                   throw new Exception("参数异常");
                }
                int len = arr.Length;
                Queue<Card> queue = new Queue<Card>(len);
                foreach (Card i in arr)
                {
                    queue.Enqueue(i);
                }
                List<string> list = new List<string>(len);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < len; i++)
                {
                    list.Add(GetItem(sb.ToString(),queue));
                    Card cur = queue.Dequeue();
                    queue.Enqueue(cur);
                    sb.Append(queue.Dequeue().ToString().PadRight(3,' ')+"  ");
                }
                return list;
            }
    
            static string GetItem(string s,Queue<Card> queue)
            { 
                StringBuilder sb = new StringBuilder(s);
                foreach (var item in queue)
                {
                    sb.Append(item.ToString().PadRight(3, ' ') + "  ");
                }
                return sb.ToString();
            }
    
            //实现翻牌的算法
            static Card[] TestArr(int size)
            {
                Card[] arr = new Card[size];
                for (int i = 0; i < size; i++)
                {
                    arr[i] = new Card();
                }
                int len = arr.Length;
                Queue<Card> queue = new Queue<Card>(len);
                foreach (Card i in arr)
                {
                    queue.Enqueue(i);
                }
                for (int i = 1; i <= len; i++)
                {
                    Card cur = queue.Dequeue();
                    queue.Enqueue(cur);
                    cur = queue.Dequeue();
                    cur.Value = i;
                }
                return arr;
            }
    复制代码

    几个截图,如果题目我说得不清楚,下面几张图应该可以让大家看得更明白

  • 相关阅读:
    ES6的模块化历史
    javaee笔记之web.xml文件内的标签到底什么意思
    iTOP4412设备驱动学习五--地址和存储的概念
    iTOP4412设备驱动学习四--嵌入式硬件研发流程PCB和原理图的查看
    iTOP4412设备驱动学习三--设备节点的生成和调用:杂项设备驱动的注册和调用
    iTOP4412设备驱动学习二--在module中注册设备
    iTOP4412设备驱动学习一--设备和驱动的注册
    Linux下阅读源代码工具安装
    结构体
    综合实例:个人银行账户管理程序
  • 原文地址:https://www.cnblogs.com/wei2yi/p/3248292.html
Copyright © 2020-2023  润新知