快速排序算法的改进

快速排序在大量数据,数据随机分布,并且重复数据较少时,性能较好。

主要作了如下改进:

1、非递归实现,防止数据量大时栈溢出。

2、对于数据是全部相等时候的改进。

3、如果数据小于一定的数目,采用插入排序。

4、中间值的选择。

测试结果:

1、1000万个随机数据,各不相同。 

List<T>类的Sort()方法:1.3秒

List<T>类的Sort(Comparison<T> comparison)方法:6.2秒

自己写的算法:3.7秒

2、1000万个随机数据,有少量相同的元素。

List<T>类的Sort()方法:1.1秒

List<T>类的Sort(Comparison<T> comparison)方法:5.7秒

自己写的算法:2.7秒

3、1000万个随机数据,有大量相同的元素。

List<T>类的Sort()方法:0.8秒

List<T>类的Sort(Comparison<T> comparison)方法:5.3秒

自己写的算法:1.7秒

4、1000万个全部相同的数据。

List<T>类的Sort()方法:0.59秒

List<T>类的Sort(Comparison<T> comparison)方法:4.7秒

自己写的算法:0.42秒

非递归实现的快速排序算法:

namespace Sort
{
    /// <summary>
    /// 快速排序(非递归实现)
    /// 2013年12月25日
    /// </summary>
    public class QuickSort
    {
        /// <summary>
        /// 快速排序的非递归实现
        /// </summary>
        /// <param name="array">排序数组</param>
        public static void Sort(int[] array)
        {
            int start = 0;
            int end = array.Length - 1;
            int[] stackLeft = new int[array.Length];
            int[] stackRight = new int[array.Length];
            int left;
            int right;
            int index = 0;

            SortUnit(array, start, end, out left, out right);

            if (left > start)
            {
                stackLeft[index] = start;
                stackRight[index] = left;
                index++;
            }

            if (right < end)
            {
                stackLeft[index] = right;
                stackRight[index] = end;
                index++;
            }

            while (index > 0)
            {
                index--;
                start = stackLeft[index];
                end = stackRight[index];

                if (end - start < 5)//排序算法执行到一定深度时,数组整体有序,局部无序,这时停止快速排序,后面将改用插入排序
                {
                    continue;
                }

                SortUnit(array, start, end, out left, out right);

                if (left > start)
                {
                    stackLeft[index] = start;
                    stackRight[index] = left;
                    index++;
                }

                if (right < end)
                {
                    stackLeft[index] = right;
                    stackRight[index] = end;
                    index++;
                }
            }

            InsertionSort(array);
        }//end of Sort

        /// <summary>
        /// 一次排序单元,完成此方法,数组分成三部分,左边的比key小,右边的比key大,中间的和key相等
        /// </summary>
        /// <param name="array">排序数组</param>
        /// <param name="start">排序起始位置</param>
        /// <param name="end">排序结束位置</param>
        /// <param name="left">当key存在相同元素时,完成排序后,中间部分的左边缘</param>
        /// <param name="right">当key存在相同元素时,完成排序后,中间部分的右边缘</param>
        private static void SortUnit(int[] array, int start, int end, out int left, out int right)
        {
            int mid = (start + end) / 2;
            int _temp = array[start];
            array[start] = array[mid];
            array[mid] = _temp;
            int key = array[start];
            int[] stackRight = new int[end - start + 1];//存放原始数组中key右边的与key相等的元素的下标
            int[] stackLeft = new int[end - start + 1];//存放原始数组中key左边的与key相等的元素的下标
            int stackRightCount = 0;
            int stackLeftCount = 0;

            while (start < end)
            {
                while (start < end && array[end] >= key)
                {
                    if (array[end] == key)
                    {
                        stackRight[stackRightCount++] = end;//把与key相等的元素的下标记录下来
                    }
                    end--;
                }
                if (start != end) array[start] = array[end];

                while (start < end && array[start] <= key)
                {
                    if (array[start] == key)
                    {
                        stackLeft[stackLeftCount++] = start;//把与key相等的元素的下标记录下来
                    }
                    start++;
                }
                if (start != end) array[end] = array[start];
            }
            array[start] = key;

            //把key右边的与key相等的元素放在key的右侧
            int i;
            int index = 0;
            for (i = start + 1; i <= start + stackRightCount; i++)
            {
                if (array[i] != key)
                {
                    int temp = array[i];
                    array[i] = array[stackRight[index]];
                    array[stackRight[index]] = temp;
                    index++;
                }
            }

            //把key左边的与key相等的元素放在key的左侧
            index = 0;
            for (i = start - 1; i >= start - stackLeftCount; i--)
            {
                if (array[i] != key)
                {
                    int temp = array[i];
                    array[i] = array[stackLeft[index]];
                    array[stackLeft[index]] = temp;
                    index++;
                }
            }

            right = start + stackRightCount + 1;
            left = start - stackLeftCount - 1;
        }//end of SortUnit

        /// <summary>
        /// 插入排序
        /// </summary>
        private static void InsertionSort(int[] array)
        {
            int i, j;
            int temp;
            for (i = 1; i < array.Length; i++)
            {
                temp = array[i];
                j = i - 1;
                //与已排序的数逐一比较,大于temp时,该数移后
                while (j >= 0 && array[j] > temp)
                {
                    array[j + 1] = array[j];
                    j--;
                }
                array[j + 1] = temp;
            }
        }
    }
}

测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace Sort
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private int[] m_data;

        /// <summary>
        /// 产生测试数据
        /// </summary>
        private int[] GetData()
        {
            if (m_data == null)
            {
                Random rnd = new Random();
                int count = 10000000;
                int __max = 1000000;
                m_data = new int[count];
                for (int i = 0; i < count; i++)
                {
                    m_data[i] = rnd.Next(1, __max + 1);
                }
                return m_data.ToArray<int>();
            }
            else
            {
                return m_data.ToArray<int>();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            DateTime dt1 = DateTime.Now;
            //=======================================================
            int[] array = GetData();
            List<int> list = array.ToList<int>();
            list.Sort();
            //=======================================================

            DateTime dt2 = DateTime.Now;
            //=======================================================
            array = GetData();
            list = array.ToList<int>();
            list.Sort((a, b) => a - b);
            //=======================================================

            DateTime dt3 = DateTime.Now;
            //=======================================================
            array = GetData();
            QuickSort.Sort(array);
            //=======================================================

            DateTime dt4 = DateTime.Now;

            //判断排序前的数组和排序后的数组的元素是否匹配
            //bool bl = ArrayComparison.compare(array, GetData());

            string t1 = dt2.Subtract(dt1).TotalMilliseconds.ToString();
            string t2 = dt3.Subtract(dt2).TotalMilliseconds.ToString();
            string t3 = dt4.Subtract(dt3).TotalMilliseconds.ToString();

            MessageBox.Show(t1 + "" + t2 + "" + t3);
        }
    }
}
原文地址:https://www.cnblogs.com/s0611163/p/3491433.html