c# 排序算法可视化

最近在 b 站上看了一个排序算法的动画,所以想自己写一个类似的项目。

项目使用 Graphics 在 winform 的窗体上绘图。(新建项目时选择控制台项目,注意添加引用:System.Drawing, System.Windows.Forms)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Sort
{
    /// <summary>
    /// 排序算法
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            FrmSort frm = new FrmSort();
            frm.ShowDialog();
        }
    }

    class FrmSort : Form
    {
        private const int length = 100; //待排序集合的宽度
        private const int width = 2;   //绘图时每个柱子的宽度
        private const int height = 2;   //绘图时每个柱子的高度放大倍数

        public FrmSort()
        {
            this.BackColor = Color.White;
            this.Width = 1000;
            this.Height = 600;
            this.Shown += new System.EventHandler(this.Frm_Shown);
        }

        private void Frm_Shown(object sender, EventArgs e)
        {
            Insert(0);
            HalfInsert(1);
            SelectSort(2);
            BubbleSort(3);
            ShellSort(4);
            MergeSort(5);
        }

        //获得随机数组
        static List<int> GetRandomList()
        {
            Random rnd = new Random(1);
            List<int> listOriginal = new List<int>();
            for (int i = 1; i < (length + 1); i++)
            {
                listOriginal.Add(i);
            }
            List<int> list = new List<int>();
            foreach (int item in listOriginal)
            {
                list.Insert(rnd.Next(list.Count), item);
            }
            return list;
        }

        static int[] GetRandomArray()
        {
            return GetRandomList().ToArray();
        }

        // 绘图
        private void Draw(List<int> valueList, List<int> reDrawIndexList, Graphics g, int xBase, int yBase)
        {
            for (int i = 0; i < reDrawIndexList.Count; i++)
            {
                int xIndex = reDrawIndexList[i];
                Pen whitePen = new Pen(Brushes.White, width);
                Pen blackPen = new Pen(Brushes.Black, width);
                Point point1 = new Point(xBase + xIndex * width, yBase);
                Point point2 = new Point(xBase + xIndex * width, yBase + length * height);
                Point point3 = new Point(xBase + xIndex * width, yBase + valueList[xIndex] * height);
                g.DrawLine(whitePen, point1, point2);
                g.DrawLine(blackPen, point1, point3);
            }
        }

        // 绘图
        private void Draw(int[] valueList, List<int> reDrawIndexList, Graphics g, int xBase, int yBase)
        {
            for (int i = 0; i < reDrawIndexList.Count; i++)
            {
                int xIndex = reDrawIndexList[i];
                Pen whitePen = new Pen(Brushes.White, width);
                Pen blackPen = new Pen(Brushes.Black, width);
                Point point1 = new Point(xBase + xIndex * width, yBase);
                Point point2 = new Point(xBase + xIndex * width, yBase + length * height);
                Point point3 = new Point(xBase + xIndex * width, yBase + valueList[xIndex] * height);
                g.DrawLine(whitePen, point1, point2);
                g.DrawLine(blackPen, point1, point3);
            }
        }

        // 绘图
        private void Draw(int myValue, int myIndex, Graphics g, int xBase, int yBase)
        {
            Pen whitePen = new Pen(Brushes.White, width);
            Pen blackPen = new Pen(Brushes.Black, width);
            Point point1 = new Point(xBase + myIndex * width, yBase);
            Point point2 = new Point(xBase + myIndex * width, yBase + length * height);
            Point point3 = new Point(xBase + myIndex * width, yBase + myValue * height);
            g.DrawLine(whitePen, point1, point2);
            g.DrawLine(blackPen, point1, point3);
        }

        private void GetBasePoint(int index, out int xBase, out int yBase)
        {
            xBase = 20 + (index % 3) * width * length * 11 / 10;
            yBase = 20 + (index / 3) * height * length * 11 / 10;
        }

        //直接插入
        //每一轮都保证左侧序列已排序, 右侧序列不断的往左侧序列中插入
        private void Insert(int place)
        {
            int xBase, yBase;
            GetBasePoint(place, out xBase, out yBase);
            int[] intArray = GetRandomArray();
            using (Graphics g = this.CreateGraphics())
            {
                List<int> listIndex = new List<int>();
                for (int i = 0; i < intArray.Length; i++)
                {
                    listIndex.Add(i);
                }
                Draw(intArray, listIndex, g, xBase, yBase);
                for (int i = 1; i < intArray.Length; i++)
                {
                    for (int j = i - 1; (j >= 0) && (intArray[j + 1] < intArray[j]); j--)
                    {
                        int temp = intArray[j + 1];
                        intArray[j + 1] = intArray[j];
                        intArray[j] = temp;
                        Draw(intArray[j], j, g, xBase, yBase);
                        Draw(intArray[j + 1], j + 1, g, xBase, yBase);
                    }
                }
            }
        }

        //折半插入
        //对直接插入进行优化,在左侧找到最佳的插入点后再插入,而不是按顺序逐个尝试
        private void HalfInsert(int place)
        {
            int xBase, yBase;
            GetBasePoint(place, out xBase, out yBase);
            List<int> list = GetRandomList();
            using (Graphics g = this.CreateGraphics())
            {
                List<int> listIndex = new List<int>();
                for (int i = 0; i < list.Count; i++)
                {
                    listIndex.Add(i);
                }
                Draw(list, listIndex, g, xBase, yBase);

                for (int i = 1; i < list.Count; i++)
                {
                    int temp = list[i];
                    int low = 0;
                    int high = i - 1;
                    while (low <= high)
                    {
                        int mid = (low + high) / 2;
                        if (temp < list[mid])
                        {
                            high = mid - 1;
                        }
                        else
                        {
                            low = mid + 1;
                        }
                        Draw(temp, mid, g, xBase, yBase);
                        Thread.Sleep(10);
                        Draw(list[mid], mid, g, xBase, yBase);
                    }
                    int myValue = list[i];
                    list.RemoveAt(i);
                    list.Insert(low, myValue);
                    listIndex.Clear();
                    for (int j = low; j <= i; j++)
                    {
                        listIndex.Add(j);
                    }
                    Draw(list, listIndex, g, xBase, yBase);
                }
            }
        }

        //选择排序
        //找出list[0- 99]中的最小值换到list[0]上
        //找出list[1- 99]中的最小值换到list[1]上
        //最后一轮:找出list[98- 99]中的最小值换到list[98]上
        private void SelectSort(int place)
        {
            int xBase, yBase;
            GetBasePoint(place, out xBase, out yBase);
            List<int> list = GetRandomList();
            using (Graphics g = this.CreateGraphics())
            {
                List<int> listIndex = new List<int>();
                for (int i = 0; i < list.Count; i++)
                {
                    listIndex.Add(i);
                }
                Draw(list, listIndex, g, xBase, yBase);
                for (int i = 0; i < list.Count; i++)
                {
                    //找出后面的最小值
                    int miniIndex = i;
                    int miniValue = list[i];
                    for (int j = i; j < list.Count; j++)
                    {
                        if (list[j] < miniValue)
                        {
                            miniIndex = j;
                            miniValue = list[j];
                        }
                    }
                    //重绘
                    if (miniIndex > i)
                    {
                        list.RemoveAt(miniIndex);
                        list.Insert(i, miniValue);
                        for (int j = i; j < miniIndex; j++)
                        {
                            Draw(list[j], j, g, xBase, yBase);
                        }
                    }
                }
            }
        }

        //冒泡排序  
        //第一轮:intArray[0] > intArray[1] ? 交换 : 不变。intArray[1] > intArray[2]  .....    intArray[98] > intArray[99] ?
        //第二轮:intArray[0] > intArray[1] ? 交换 : 不变。intArray[1] > intArray[2]  .....    intArray[97] > intArray[98] ?
        //最后一轮:intArray[0] > intArray[1] ?
        private void BubbleSort(int place)
        {
            int xBase, yBase;
            GetBasePoint(place, out xBase, out yBase);
            int[] intArray = GetRandomArray();
            using (Graphics g = this.CreateGraphics())
            {
                List<int> listIndex = new List<int>();
                for (int i = 0; i < intArray.Length; i++)
                {
                    listIndex.Add(i);
                }
                Draw(intArray, listIndex, g, xBase, yBase);
                for (int i = intArray.Length; i > 0; i--)
                {
                    for (int j = 0; j < i - 1; j++)
                    {
                        if (intArray[j] > intArray[j + 1])
                        {
                            int temp = intArray[j];
                            intArray[j] = intArray[j + 1];
                            intArray[j + 1] = temp;
                            Draw(intArray[j], j, g, xBase, yBase);
                            Draw(intArray[j + 1], j + 1, g, xBase, yBase);
                            Thread.Sleep(1);
                        }
                    }
                }
            }
        }

        //希尔排序
        private void ShellSort(int place)
        {
            int xBase, yBase;
            GetBasePoint(place, out xBase, out yBase);
            int[] intArray = GetRandomArray();
            using (Graphics g = this.CreateGraphics())
            {
                List<int> listIndex = new List<int>();
                for (int i = 0; i < intArray.Length; i++)
                {
                    listIndex.Add(i);
                }
                Draw(intArray, listIndex, g, xBase, yBase);
                for (int step = intArray.Length / 2; step >= 1; step = step / 2) //增量递减到1使完成排序
                {
                    for (int i = step; i < intArray.Length; i++)   //插入排序的一轮
                    {
                        int temp = intArray[i];
                        int j = 0;
                        for (j = i - step; (j >= 0) && (intArray[j] > temp); j = j - step)
                        {
                            intArray[j + step] = intArray[j];
                            Draw(intArray[j + step], j + step, g, xBase, yBase);
                            Thread.Sleep(10);
                        }
                        intArray[j + step] = temp;
                        Draw(intArray[j + step], j + step, g, xBase, yBase);
                    }
                }
            }
        }

        #region 归并排序
        public void MergeSort(int place)
        {
            int xBase, yBase;
            GetBasePoint(place, out xBase, out yBase);
            int[] intArray = GetRandomArray();
            using (Graphics g = this.CreateGraphics())
            {
                List<int> listIndex = new List<int>();
                for (int i = 0; i < intArray.Length; i++)
                {
                    listIndex.Add(i);
                }
                Draw(intArray, listIndex, g, xBase, yBase);
                MergeSort(intArray, 0, intArray.Length - 1, g, xBase, yBase);
            }
        }

        private void MergeSort(int[] array, int p, int r, Graphics g, int xBase, int yBase)
        {
            if (p < r)
            {
                int q = (p + r) / 2;
                MergeSort(array, p, q, g, xBase, yBase);
                MergeSort(array, q + 1, r, g, xBase, yBase);
                Merge(array, p, q, r, g, xBase, yBase);
            }
        }

        private void Merge(int[] array, int p, int q, int r, Graphics g, int xBase, int yBase)
        {
            int[] L = new int[q - p + 2];
            int[] R = new int[r - q + 1];
            L[q - p + 1] = int.MaxValue;
            R[r - q] = int.MaxValue;

            for (int i = 0; i < q - p + 1; i++)
            {
                L[i] = array[p + i];
            }

            for (int i = 0; i < r - q; i++)
            {
                R[i] = array[q + 1 + i];
            }

            int j = 0;
            int k = 0;
            for (int i = 0; i < r - p + 1; i++)
            {
                if (L[j] <= R[k])
                {
                    array[p + i] = L[j];
                    j++;
                }
                else
                {
                    array[p + i] = R[k];
                    k++;
                }
                Draw(array[p + i], p + i, g, xBase, yBase);
                Thread.Sleep(10);
            }
        }
        #endregion
    }
}

  

原文地址:https://www.cnblogs.com/aitong/p/10959613.html