算法-“冒泡排序”程序模拟

作者:vuefine
文献:
- Data Structures and Algorithms Using C# |Michael Mcmillan
平台:.NET 2.0+


冒泡排序

排序最基础最基本的算法便是冒泡排序了,bubble sort,最基本的往往最能反映排序的基本思想,基本思路,尽管它做了很多次冗余的比较。

模拟思路

在.NET中通过Random,生成随机数,我们首先建立一个MyArray类,在这个类中内部引用了Array对象,提供的功能包括:

  • 插入MyElement 元素
  • 生成随机数集合
  • 访问元素
  • 清零
  • 打印所有元素
  • 元素交换

客户端调用模型,如果比较并发生了交换,记录下来,这样我们能看到这10个元素的比较和交换历程。为了方便阅读,这里只列出精简版,冒泡排序最核心的代码,控制台相关的代码省略。

        static void Main(string[] args)
        {
            int size = 10;
            MyArray myarr = new MyArray(size);
            myarr.FillRandomValue();
            //由小到大排序
            for (int outer = 0; outer < size; outer++)
            {
                for (int inner = outer + 1; inner < size; inner++)
                {
                    if (myarr.GetAt(outer).Val > myarr.GetAt(inner).Val)
                    {                     
                        MyArray.Swap(myarr.GetAt(outer), myarr.GetAt(inner));
                    }
                }          
            }
        }

模拟结果

每一步发生的交换记录结果如下,可以看到随机生成的集合元素(个数设置为10个)位于黄颜色标注的框内。
第1轮比较,共计发生了3次交换,这轮过后,我们能找出这10个元素的最小值为8,并且我们看到在索引位置0处,元素值一共发生了3次改变,分别为24,11,8。
第2轮比较,索引1~9找出最小值为11。
第3轮比较,索引2~9找出最小值12。
第4轮比较,索引3~9找出最小值15。
第5轮比较,索引4~9找出最小值24。
第6轮比较,索引5~9找出最小值26。
第7轮比较,索引6~9找出最小值35。
第8轮比较,索引7~9找出最小值35。
第9轮比较,索引8~9找出最小值39。
最后只剩下一个元素,没做任何比较,直接退出。
最终经过9轮比较,共计27次交换,最终完成的集合元素的升序排列。


算法-“冒泡排序”程序模拟_第1张图片

大家通过上图可以看到冒泡排序算法的基本思路,每经过一轮比较,无序序列中最小值就位。

冗余比较

冒泡排序这些比较中哪些是超过1次的相同的元素比较呢?利用.Net提供的Linq技术。打印出结果如下图所示:


算法-“冒泡排序”程序模拟_第2张图片

从图中看出,39和42,24和35,都是比较了6次啊!24和35比较了5次啊!由上图可知,我们看到冒泡排序确实会出现很多次重复比较,要知道这才是排序10个元素啊,这都出现了两个元素重复比较6次情况!

总结

冒泡排序共计需要n*(n-1)/2次比较,大o意义上为n的平方,才最终将无序序列变为有序。那么有没有更优秀的排序方法呢?

请参考模拟“插入排序”算法!


附录

模拟冒泡排序用到的代码,MyArray对象

```
    public class MyArray
    {
        private MyElement[] _array;
        private int _upper;
        private int _cnt;
        private  readonly int _capacity;
        public MyArray(int size)
        {
            _capacity = size;
            _array = new MyElement[size];
            _upper = size - 1;
            _cnt = 0;
        }

        public void Insert(MyElement item)
        {
            _array[_cnt++] = item;
        }

        public void Clear()
        {
            for (int i = 0; i < _cnt; i++)
                _array[i].Val = 0;
            _cnt = 0;
        }

        public override string ToString()
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach(var item in _array)
            {
                stringBuilder.Append(item.Val + " ");
            }
            return stringBuilder.ToString();
        }

        public  void FillRandomValue()
        {
            Random random = new Random(_capacity*5);
            for (int i = 0; i < _capacity; i++)
            {
                var element = new MyElement();
                element.Val = (int)(random.NextDouble() * _capacity * 5);
                this.Insert(element);
            }
        }

        public void Printf()
        {
            Console.Write(this.ToString());
        }

        public MyElement GetAt(int index)
        {
            if (index < 0 || index > _capacity)
                throw new ArgumentException();
            return _array[index];
        }

        //如果a>b,交换;否则直接return
        public static void Swap(MyElement a,MyElement b)
        {
            if (a.Val <= b.Val) return;
            int t = a.Val;
            if(a.Val>b.Val)
            {
                a.Val = b.Val;
                b.Val = t;
            }
        }
    }

里面嵌套的元素类,实现了可以比较IComparable的操作接口,根据元素的Val属性判断元素的大小关系!

    public class MyElement: IComparable
    {
        public int Val { get; set; }

        public int CompareTo(object b)
        {
            if (this.Val < (b as MyElement).Val) return -1;
            else if (this.Val == (b as MyElement).Val) return 0;
            else return 1;
        }
    }

Linq查重:

```
        static void printfDuplicateCompare(List compares)
        {
            //按组合键分组后,每组元素个数大于2的分组,按降序排序
            var rtnByVal1 = from item in compares
                            group item by new { item.Val1, item.Val2 }
                                into g
                                where g.Count()>1
                                orderby g.Count() descending
                                select g;
            //按Val1和Val2组合为字典键,元素个数为值
            var dict = rtnByVal1.ToDictionary(g => g.Key,g=>g.Count());

            foreach (var item in dict)
            {
                Console.Write(string.Format("{0} 和{1} 比较了{2}次\n",item.Key.Val1,item.Key.Val2,item.Value));
            }
        }

以上所有代码的下载地址为:


用C#描述数据结构4:模拟冒泡排序过程,比较次数分析

你可能感兴趣的:(算法/LeetCode,模拟排序算法,经典算法,LeetCode题目研究)