c#插入排序、希尔排序、快速排序三种排序的解释

142 阅读2分钟

1.插入排序

g.gif

  • 原理 将数组中的数分为左边排序区和右边的未排序区,每次拿未排序区中的第一个值和排序区中的值进行对比,如果比排序区中的值大则交换两个的值然后再继续往前判断直到判断到左边的值没有比右边的值大的时候,那么这个位置就是刚才未排序区第一个值在排序区中的位置,接下来继续判断下一个未排序区的值一次类推直到最后一个值 image.png

image.png

namespace 插入排序
{
    internal class Program
    {
        static void Main(string[] args)
        {
           
            //插入排序分为排序区和未排序区,排序区从第一个元素开始  
            int[] newArray = new int[] {9,10,34,21,0,3,1};
            int temp = newArray[0];
            //从未排序区的第一个元素开始遍历,每一次确定一个未排序区中的值,
            //找到它在排序区中合适的位置然后插入   
            for (int i=1;i<newArray.Length;i++)
            {
                for (int j=i;j>0;j--)//拿当前第i个的值和排序区中的值进行比对找到合适的位置
                {
                    if (newArray[j - 1] < newArray[j]) break;
                    //如果比左边的值要小交换值 
                    temp = newArray[j];
                    newArray[j] = newArray[j - 1];
                    newArray[j - 1] = temp;
                }
            }
            Console.WriteLine(String.Join(" ",newArray));

        }
    }
}

插入排序和冒泡排序的优异点:

冒泡排序和插入排序都是两层for循环,时间复杂度O(n) 区别在于:

1.冒泡排序是拿一个元素和无序序列去遍历比较,比较得到整个无序序列中最值,然后放入有序序列,而一旦放入有序序列,就不再碰了 冒泡排序的当前元素是无论如何不会触摸有序序列的 非常生动的体现了冒泡的情形,泡泡是乱的,最大的泡泡在大大小小杂乱无章的泡泡群中漂浮到最上面 而插入排序呢恰恰相反 插入排序是拿一个元素和有序的数列去比,从单一元素的假有序一个一个加,拿一个元素进入有序序列,碰到比自己大或小的就即刻坐下,不再继续比较 插入排序的当前元素是无论如何不会触摸无序序列的

2.冒泡排序因为是无序,所以你即使遇到下一个比自己大,你不知道后面有没有更大的,你只能换一下,把手中的换成刚刚比较出更大的,去比接下来的 冒泡的每一次冒,都要把无序序列轮一遍 插入排序恰恰相反,一旦你遇到比自己大或小的了,你就知道,后面都是比自己大或小的,就没必要再继续往前走了,现在坐下,当前元素就进入了有序序列 插入的每一次插,都不一定要轮一遍有序序列

相对于冒泡排序,插入排序可以简化比较次数,因为不但的交换值需要开辟空间,会大大消耗内存,而插入排序可以在算法优异程度上更优于冒泡排序。

2.希尔排序

  • 原理

image.png image.png

namespace ConsoleApp8
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] intArray = new int[] {23 , 3 , 45, 6 , 10, 8 , 1};
            int temp = intArray[0];
            for (int step=intArray.Length/2;step>=1;step/=2)//步长的一个变化  
            {
                //每一轮进行步长为step的插入排序 
                for (int start=step;start<intArray.Length;start++)
                {
                    //要拿当前未排序区的每一个值和左边的值进行对比,而且是每隔一个步长为step进行对比
                    for (int s=start;s>=step;s-=step)
                    {
                        //如果左边比右边大交换值
                        if (intArray[s] < intArray[s-step])  //s-step>=0    
                        {
                            temp = intArray[s];
                            intArray[s] = intArray[s - step];
                            intArray[s - step] = temp;
                        }

                    }
                }
            }
            Console.WriteLine(String.Join(" ",intArray));
        }
    }
}
复制代码

3.快速排序

int[] intArray = new int[] { 2, 5, 8, 19, 22, 15, 21, 4 };
            //创建一个方法 这个方法要传入中间值,起始的游标,结束的游标
            int start = 0;
            int end = intArray.Length - 1;

            void getMiddle(int s, int e)
            {

                int start = s;
                int end = e;
                if (s == e || s > e)
                    return;
                int mid = intArray[start];
                while (end > start)
                {
                    //一开始从最右边开始比对
                    while (intArray[end] >= mid && start < end)
                    {
                        //什么时候最后游标才进行减减,就是右边的值比mid大
                        end--;

                    }
                    //到外面来说明 end对应的下标的值要比mid小,把end的赋值给start位置
                    intArray[start] = intArray[end];

                    while (intArray[start] <= mid && start < end)
                    {
                        start++;

                    }
                    //到这里说明有一个比它还大那么就将当前start下标对应的值赋值给end下标对应的值
                    intArray[end] = intArray[start];

                }
                //到这里说明中间值位置找到了,要在这个位置插入中间值
                intArray[end] = mid;
                //对子序列进行同样的操作
                getMiddle(s, end - 1);
                getMiddle(end + 1, e);
            }
            getMiddle(start, end);
            Console.WriteLine(string.Join(" ", intArray));