排序

排序

        排序(Sort)是计算机程序设计中的一种重要操作,也是日常生活中经常遇到的问题。例如,字典中的单词是以字母的顺序排列,否则,使用起来非常困难。同样,存储在计算机中的数据的次序,对于处理这些数据的算法的速度和简便性而言,也具有非常深远的意义。

        排序是把一个记录(在排序中把数据元素称为记录)集合或序列重新排列成按记录的某个数据项值递增(或递减)的序列。

        下表是一个学生成绩表,其中某个学生记录包括学号、姓名及计算机文化基础、C语言、数据结构等课程的成绩和总成绩等数据项。在排序时,如果用总成绩来排序,则会得到一个有序序列;如果以数据结构成绩进行排序,则会得到另一个有序序列。

        作为排序依据的数据项称为“排序项”,也称为记录的关键码(Keyword)。关键码分为主关键码(PrimaryKeyword)和次关键码(SecondaryKeyword)。一般地,若关键码是主关键码,则对于任意待排序的序列,经排序后得到的结果是唯一的;若关键码是次关键码,排序的结果不一定唯一,这是因为待排序的序列中可能存在具有相同关键码值的记录。此时,这些记录在排序结果中,它们之间的位置关系与排序前不一定保持一致。如果使用某个排序方法对任意的记录序列按关键码进行排序,相同关键码值的记录之间的位置关系与排序前一致,则称此排序方法是稳定的;如果不一致,则称此排序方法是不稳定的。

        由于待排序的记录的数量不同,使得排序过程中涉及的存储器不同,可将排序方法分为内部排序(InternalSorting)和外部排序(External Sorting)两大类。

        内部排序指的是在排序的整个过程中,记录全部存放在计算机的内存中,并且在内存中调整记录之间的相对位置,在此期间没有进行内、外存的数据交换。外部排序指的是在排序过程中,记录的主要部分存放在外存中,借助于内存逐步调整记录之间的相对位置。在这个过程中,需要不断地在内、外存之间交换数据。

1. 直接插入排序

        插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

        插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

1.2 直接插入排序代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _406_直接插入排序
{
    class Program
    {
        static void InsertSort(int[] dataArray)
        {
            for(int i=1;i<dataArray.Length;i++)
            {
                int iValue = dataArray[i];
                bool isInsert = false;
                //拿到i位置的元素,跟前面的所有元素比较
                //如果比i大,就让他向后移动
                for (int j=i-1;j>=0;j--)
                {
                    if(dataArray[j]>iValue)
                    {
                        dataArray[j + 1] = dataArray[j];
                        
                    }
                    else
                    {
                        //发现一个比i小的值就不移动了
                        dataArray[j + 1] = iValue;
                        isInsert = true;
                        break;
                    }
                }
                if(isInsert==false)
                {
                    dataArray[0] = iValue;
                }
            }
        }
        static void Main(string[] args)
        {
            int[] intArray = new int[] { 2,4,667,8,989,342,2332,45,7};
            InsertSort(intArray);

            foreach(var temp in intArray)
            {
                Console.Write(temp + " ");
            }

            Console.ReadKey();

        }
    }
}

2. 冒泡排序

        冒泡排序(BubbleSort)的基本思想是:将相邻的记录的关键码进行比较,若前面记录的关键码大于后面记录的关键码,则将它们交换,否则不交换。

3. 简单选择排序

        简单选择排序(SimpleSelectSort)算法的基本思想是:从待排序的记录序列中选择关键码最小(或最大)的记录并将它与序列中的第一个记录交换位置;然后从不包括第一个位置上的记录序列中选择关键码最小(或最大)的记录并将它与序列中的第二个记录交换位置;如此重复,直到序列中只剩下一个记录为止。


3.1 简单选择排序代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _407_简单选择排序
{
    class Program
    {
        static void SelectSort(int[] dataArray)
        {
            for(int i=0;i<dataArray.Length-1;i++)
            {
                int minValue = dataArray[i];
                int minIndex = i;//储存最小值所在索引
                for(int j=i+1;j<dataArray.Length;j++)
                {
                    if(dataArray[j]<minValue)
                    {
                        minValue = dataArray[j];
                        minIndex = j;
                    }
                }
                if(minIndex!=i)
                {
                    int temp = dataArray[i];
                    dataArray[i] = dataArray[minIndex];
                    dataArray[minIndex] = temp;
                }
            }
        }
        static void Main(string[] args)
        {
            int[] intArray = new int[] { 2, 4, 667, 8, 989, 342, 2332, 45, 7 };
            SelectSort(intArray);

            foreach (var temp in intArray)
            {
                Console.Write(temp + " ");
            }

            Console.ReadKey();
        }
    }
}

4. 快速排序

        快速排序由于排序效率综合来说你几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影。

        快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

        该方法的基本思想是:

1.先从数列中取出一个数作为基准数。

2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。

3.再对左右区间重复第二步,直到各区间只有一个数。

4.1 思想

        以一个数组作为示例,取区间第一个数为基准数。


        初始时,i= 0;  j = 9;   X = a[i] = 72

        由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。

        从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8];i++; 这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3];j--;

数组变为:


i =3;   j = 7;   X=72

再重复上面的步骤,先从后向前找,再从前向后找。

从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3]= a[5]; i++

从i开始向后找,当i=5时,由于i==j退出。

此时,i= j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。

数组变为:

可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。

快排总结

1.i=L; j = R; 将基准数挖出形成第一个坑a[i]。

2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。

3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。

4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。

4.2 快速排序代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _408_快速排序
{
    class Program
    {
        /// <summary>
        /// 对数组dataArray中索引从left到right之间的数做排序
        /// </summary>
        /// <param name="dataArray">要排序的数组</param>
        /// <param name="left">要排序数据的开始索引</param>
        /// <param name="right">要排序数据的结束索引</param>
        static void QuickSort(int[] dataArray,int left,int right)
        {
            if(left<right)
            {
                int x = dataArray[left];//基准数,把比他小或者等于他的放在他的左边,然后把比他大的放在他的右边
                int i = left;
                int j = right;//用来做循环的标志位


                while (true&&i<j)//当i==j的时候,说明我们找到了一个中间位置,这个中间位置就应该是基准数的位置
                {
                    //从后往前比较(从右到左比较找一个比X小或者等于的数字,放在坑里面,坑位于i位置
                    while (true && i < j)
                    {
                        if (dataArray[j] <= x)//找到了一个比基准数小或者等于的数字,应该将它放在x左边
                        {
                            dataArray[i] = dataArray[j];
                            break;
                        }
                        else
                        {
                            j--;//向左移动,到下一个数字,然后比较
                        }
                    }

                    //从前往后(从左往右)找一个比X大的数字,放在坑里面,现在的坑位于j的位置
                    while (true && i < j)
                    {
                        if (dataArray[i] >= x)
                        {
                            dataArray[j] = dataArray[i];
                            break;
                        }
                        else
                        {
                            i++;
                        }
                    }
                }

                //跳出循环,现在i==j i是中间位置
                dataArray[i] = x;//left-i-right

                QuickSort(dataArray, left, i - 1);
                QuickSort(dataArray, i + 1, right);
            }
        }
        static void Main(string[] args)
        {
            int[] intArray = new int[] { 2, 4, 667, 8, 989, 342, 2332, 45, 7 };
            QuickSort(intArray,0,intArray.Length-1);

            foreach (var temp in intArray)
            {
                Console.Write(temp + " ");
            }

            Console.ReadKey();
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王大匣

你的鼓励是我创作最大动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值