剑指offer:排序算法实现经验教训总结

前言:写这篇博客主要是加深自己对排序算法的理解和总结实现算法时的一些经验和教训,如果有错误请指出,感谢

  这个是关于算法的思维导图,自己把基于比较的7个算法,写了一个思维导图。思维导图软件使用的是XMind,有免费版感兴趣可以下载。

  本文主要分为两个部分,一个是对于算法的理解另一个是在算法实现过程中一些经验和教训的总结。

  一,关于算法

  首先推荐一个帖子http://blog.csdn.net/ctang/article/details/37914 这个是对于算法分析比较好的,在算法实现过程中需要注意的是快排和归并排序需要使用堆栈或者递归实现。对于快速排序当数据本身有序时会退化到O(N*N)的时间复杂度中,如果是大数据(我在测试中对于11000以上的有序数据量,就会出现堆栈溢出的异常),因此需要采用非递归,自己使用堆栈比较好。

  二、算法实现中的经验和教训

  最开始时只是用了一个Isort接口,一共7个算法希望用一个类去实现,在实现过程中,发现这种实现方法太过于复杂,因为有的算法还需要辅助函数。

    public interface ISort
    {
        void SelectSort();
        void BubbleSort();
        void QuickSort();
        void InsertSort();
        void ShellSort();
        void MergeSort();
        void HeapSort();
    }

  之后就设计了另一个接口IAlgorithmSort ,只用一个Sort方法,参数用于指示是正排序还是逆排序 。

    public interface IAlgorithmSort     
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="LittleToBig"> 1....to....n or n....to...1 </param>
        void Sort(bool LittleToBig);
    }

  设计一个AlgorithmSort类继承IAlgorithmSort接口,因为它没有具体实现的排序方法,所以把它定义为abstract抽象类,不可以实例化。AlgorithmSort主要提供一些排序中需要的共有方法和数据:1按照要求生成数据(逆序,正序,随机)2打印数据3查看数据是否有序4交换数据。具体的排序时由两个抽象方法实现的,见下面代码。

        public void Sort(bool LittleToBig) 
        {
            if (LittleToBig)
                SortPositive();
            else
                SortNegitive();
        }
        public abstract void SortPositive();
        public abstract void SortNegitive();

  请注意public abstract void SortPositive();把数据正排序,这个方法是一个虚方法,它的访问属性是public,当我尝试在子类改变它的访问符时出错,请注意无论是abstract还是Virtual 子类都不可以更改它的访问属性。SortPositive()和SortNegitive()是否应该放在IAlgorithmSort接口中,我也有点犹豫,我尝试放在接口中时,发现对于接口中的方法,如果不想实现时可以在方法前加abstract关键字,代价是不可以实例化。

  所有算法实现后就有一个测试问题,为了方便测试AlgorithmSort类中可以生成随机数据,随机正序数据和随机逆序数据,最开始设计的时候是每次进行排序检测时,都调用一下随机函数,然后排序,实践过程中发现,每次生成随机数据时间消耗太大,因此有增加了几个变量,函数初始化时就生成相关的数据。

  _data 是每次排序时要用的数据,_xrData是随机数据,_prData是随机正序数据,_nrData时随机逆序数据,每次排序前_data需要复制相关的数据。

        protected const int LENGTH = 10000;
        private Random _random; 
        protected int [] _data;
        private int[] _xrData;
        private int[] _prData;
        private int[] _nrData;

  AlgorithmSort类中还设置了一个CheckPorder函数和CheckNorder函数用来检查排序结果是否符合预期,当然这两个函数放在Test类中比较合适。

  

这个函数的好处是可以通过颜色通知是否符合预期。

  AlgorithmSort类的源代码

  

AlgorithmSort类的源代码
    public interface IAlgorithmSort     
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="LittleToBig"> 1....to....n or n....to...1 </param>
        void Sort(bool LittleToBig);
    }
    public abstract class AlgorithmSort : IAlgorithmSort
    {
        protected const int LENGTH = 10000;
        private Random _random; 
        protected int [] _data;
        private int[] _xrData;
        private int[] _prData;
        private int[] _nrData;
        protected AlgorithmSort() 
        {
            _random = new Random();
            _data = new int[LENGTH];
            _xrData = new int[LENGTH];
            _prData=new int[LENGTH];
            _nrData=new int[LENGTH]; 
            newRandomData();
            newRandomPositiveOrderData();
            newRandomNegitiveOrderData();
            //RandomData();
        }
        private void newRandomData() 
        {
            for (int i = 0; i < LENGTH; i++)
            {
                //_data[i] = _random.Next(-2 * LENGTH, 2 * LENGTH);
                _xrData[i] = _random.Next(-2 * LENGTH, 2 * LENGTH); 
            }
        }
        private void newRandomPositiveOrderData() 
        {
            int temp = -LENGTH;
            for (int i = 0; i < LENGTH; i++)
            {
                temp = temp + _random.Next(0, 10);
                _prData[i] = temp;
            }
        }
        private void newRandomNegitiveOrderData() 
        {
            int temp = LENGTH;
            for (int i = 0; i < LENGTH; i++)
            {
                temp = temp + _random.Next(-10, 0);
                //_data[i] = temp;
                _nrData[i] = temp;
            }

        }
        public void RandomData() 
        {
            //for (int i = 0; i < LENGTH; i++)
            //    _data[i] = _random.Next(-2*LENGTH,2*LENGTH);

            for (int i = 0; i < LENGTH; i++) 
            {
                _data[i]=_xrData[i];
            }
        }
        public void RandomPositiveOrderData() 
        {
            //int temp = -LENGTH;
            //for (int i = 0; i < LENGTH; i++)
            //{
            //    temp = temp + _random.Next(0, 10);
            //    _data[i] = temp;
            //}
            for (int i = 0; i < LENGTH; i++)
            {
                _data[i] = _prData[i];
            }
        }
        public void PositiveOrderData() 
        {
            for (int i = 0; i < LENGTH; i++)
            {
                _data[i] = i+1;
            }
        }
        public void NegitiveOrderData()
        {
            for (int i = 0; i < LENGTH; i++)
            {               
                _data[i] =LENGTH-i;
            }
        }
        public void RandomNegitiveOrderData() 
        {
            //int temp = LENGTH;
            //for (int i = 0; i < LENGTH; i++)
            //{
            //    temp = temp + _random.Next(-10, 0);
            //    _data[i] = temp;
            //}
            for (int i = 0; i < LENGTH; i++)
            {
                _data[i] = _nrData[i];
            }
        }
        public void Sort(bool LittleToBig) 
        {
            if (LittleToBig)
                SortPositive();
            else
                SortNegitive();
        }
        public abstract void SortPositive();
        public abstract void SortNegitive();
        public void  Print()
        {
            foreach(int ele in _data)
            {
                Console.WriteLine(ele);
            }
        }
        protected void swap(ref int a,ref int b) 
        {
            int c;
            c = a;
            a = b;
            b = c;
        }
        public void CheckNOrder() 
        {
            bool right=true;
            for (int i = 1; i < LENGTH; i++) 
            {
                if (_data[i - 1] < _data[i]) 
                {
                    right = false;
                    break;
                }
            }
            ConsoleColor currentForeColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            if (right)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("IS Negitive Order");
            }

            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Warning Warning Warning Is NOT Negitive Order");
            }
                
            Console.ForegroundColor = currentForeColor;
        }
        public void CheckPOrder() 
        {
            bool right = true;
            for (int i = 1; i < LENGTH; i++)
            {
                if (_data[i - 1] > _data[i])
                {
                    right = false;
                    break;
                }
            }
            ConsoleColor currentForeColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            if (right)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("IS Positive Order");
            }

            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Warning Warning Warning Is NOT Positive Order");
            }

            Console.ForegroundColor = currentForeColor;
        }
    }

三关于性能测试

  性能测试使用的是老赵提供的一个简单的性能计数器:CodeTimer ,和自己写的一个Test类,主要可以通过AlgorithmSort 作为一个指针,指向子类,可以测试各种各种具体的排序方法的性能。

   函数命名解释:举例Test_N_Random_X ,Test表示是一个测试函数;N表示排序的结果时Negitive即逆序,P代表正序;Random代表使用的数据时随机生成的,X代表随机生成的数据没有顺序,P代表随机生成的数据是正序N则代表是随机生成的数据是逆序,Test_N_Random_X的意思是使用随机无序的数据,实现正排序。

  详见代码。 

Test源代码
    public class Test
    {
        private AlgorithmSort _testAlg;
        public Test(AlgorithmSort alg)
        {
            _testAlg = alg;
        }
        public void BindAlg(AlgorithmSort alg) 
        {
            if (alg == null)
                return;
            _testAlg = alg;
        }
        public void Test_P_Random_X() 
        {
            _testAlg.RandomData();
            _testAlg.SortPositive();
        }
        public void Test_N_Random_X() 
        {
            _testAlg.RandomData();
            _testAlg.SortNegitive();
        }
        public void Test_P_Random_N() 
        {
            _testAlg.RandomNegitiveOrderData();
            _testAlg.SortPositive();
        }
        public void Test_N_Random_P() 
        {
            _testAlg.RandomPositiveOrderData();
            _testAlg.SortNegitive();
        }
        public void Pack_Test(string algName) 
        {
            string testStr = "测试{0}";
            testStr = string.Format(testStr,algName);
            CodeTimer.Time(testStr+"随机逆排序", 1, Test_N_Random_X);
            CodeTimer.Time(testStr + "随机正排序", 1, Test_P_Random_X);
            CodeTimer.Time(testStr + "正序逆排", 1, Test_N_Random_P);
            CodeTimer.Time(testStr + "逆序正排", 1, Test_P_Random_N);
        }
        public void Pack_OutTest(string algName)
        {
            string testStr = "测试{0}";
            testStr = string.Format(testStr, algName);
            CodeTimer.Time(testStr + "随机逆排序", 1, Test_N_Random_X);
            _testAlg.CheckNOrder();
            CodeTimer.Time(testStr + "随机正排序", 1, Test_P_Random_X);
            _testAlg.CheckPOrder();
            CodeTimer.Time(testStr + "正序逆排", 1, Test_N_Random_P);
            _testAlg.CheckNOrder();
            CodeTimer.Time(testStr + "逆序正排", 1, Test_P_Random_N);
            _testAlg.CheckPOrder();
        }
    }

  下图是部分测试效果图

  

  全部代码下载 https://files.cnblogs.com/CaiBaoZi/Sort.rar

原文地址:https://www.cnblogs.com/CaiBaoZi/p/3022348.html