• 常用算法——排序(一)


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

    排序分为:外部排序 and 内部排序

    这里我们讨论内部排序

    image_thumb1

    冒泡排序法

    冒泡排序法的基本思想是:对待排序记录关键字从后往前(逆序)进行多遍扫描,当发现相邻两个关键字的次序与排序要求的规则不符时,就将这两个记录进行交换。这样,关键字较小的记录将逐渐从后面向前面移动,就象气泡在水中向上浮一样,所以该算法也称为气泡排序法。

    image_thumb3                                  image_thumb5

    编写一个随机生成数列的函数<CreateData>:

    #include <stdlib.h>
    int CreateData(int arr[],int n,int min,int max) //创建一个随机数组,a保存生成的数据,n为数组元素的数量 
    {
        int i,j,flag;
        srand(time(NULL));
        if((max-min+1)<n) return 0; //最大数与最小数之差小于产生数组的数量,生成数据不成功 
        for(i=0;i<n;i++)
        {
            do
            {
                arr[i]=(max-min+1)*rand()/(RAND_MAX+1)+min;
                flag=0;
                for(j=0;j<i;j++)
                {
                    if(arr[i]==arr[j])
                        flag=1;
                }
            }while(flag);        
        }
        return 1;
    }

    编写冒泡排序法程序:

    void BubbleSort(int a[],int n)
    {
        int i,j,t;
        for(i=0;i<n-1;i++)
        {
            for(j=n-1;j>i;j--)
            {
                if(a[j-1]>a[j])
                {
                    t=a[j-1];
                    a[j-1]=a[j];
                    a[j]=t;
                }
            }
            printf("第%2d遍:",i+1); 
            for(j=0;j<n;j++)
                printf("%d ",a[j]);
            printf("
    ");
        }
    }

    测试:

    int main()
    {
        int i,a[ARRAYLEN];
        for(i=0;i<ARRAYLEN;i++)
            a[i]=0;
        if(!CreateData(a,ARRAYLEN,1,100))
        {
            printf("生成随机数不成功!
    ");
            getch();
            return 1;
        }
        printf("原数据:"); 
        for(i=0;i<ARRAYLEN;i++)
            printf("%d ",a[i]);
        printf("
    ");
        BubbleSort(a,ARRAYLEN);
        printf("排序后:"); 
        for(i=0;i<ARRAYLEN;i++)
            printf("%d ",a[i]);
        printf("
    ");
        getch();
        return 0;   
    }

    结果:

    image_thumb8

    我们发现,在第三遍时我们就已经排序完毕,可是还是进行了第四第五遍,所以为了提升冒泡排序法的效率,可对BubbleSort函数进行改进,当在某一遍扫描时,发现数据都已经按顺序排列了,就不再进行后继的扫描,而结束排序过程。

    该进就是对其添加了一个标志位,当已经排序好之后,就加上标志位不再排序。

    void BubbleSort1(int a[],int n)
    {
        int i,j,t,flag=0;        //flag用来标记是否发生交换
        for(i=0;i<n-1;i++)
        {
            for(j=n-1;j>i;j--)
            {
                if(a[j-1]>a[j])//交换数据 
                {
                    t=a[j-1];
                    a[j-1]=a[j];
                    a[j]=t;
                    flag=1;
                }
            }
            printf("第%2d遍:",i+1); 
            for(j=0;j<n;j++)
                printf("%d ",a[j]);
            printf("
    ");
            if(flag==0)    //没发生交换,直接跳出循环
                break;
            else
                flag=0;
        }
    }

    快速排序法

    快速排序使用分治策略来把待排序数据序列分为两个子序列,具体步骤为:
    (1)从数列中挑出一个元素,称该元素为“基准”。
    (2)扫描一遍数列,将所有比“基准”小的元素排在基准前面,所有比“基准”大的元素排在基准后面。
    (3)通过递归,将各子序列划分为更小的序列,直到把小于基准值元素的子数列和大于基准值元素的子数列排序。

    快速排序详细步骤:

    以一个数组作为示例,取区间第一个数为基准数。
    初始时,i = 0;  j = 9;   X = a[i] = 72image_thumb10
    由于已经将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--;
    数组变为:
    image_thumb11

    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]。
    数组变为:
    image_thumb12
    可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。

    /// <summary>
            /// 对数组dataArray中索引从left到right之间的数做排序
            /// </summary>
            /// <param name="dataArray"></param>
            /// <param name="left">要排序数组的开始索引</param>
            /// <param name="right">要排序数组的结束索引</param>
            private 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)
                    {
                        //从右向左比较
                        while (true && i < j)
                        {
                            if (dataArray[j] <= x) //找到了一个比基准数 小于等于的数字 应该把它放在x的左边
                            {
                                dataArray[i] = dataArray[j];
                                break;
                            }
                            else
                            {
                                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[] data = new int[] { 42, 20, 17, 27, 13, 8, 17, 48 };
                
                QuickSort(data,0,data.Length-1);
    
                foreach (var temp in data)
                {
                    Console.Write(temp + " ");
                }
    
                Console.ReadKey();
            }

    结果:

    image_thumb14

    因为可能数据量比较小 所以看不出前二种方法的区别 可以试着增加数据量比较一下

  • 相关阅读:
    JavaScript基础1
    iOS开发之Quzrtz2D 一:认识Quzrtz2D
    ios开发抽屉效果的封装使用
    ios开发手势处理之手势识别二
    ios开发之手势处理 之手势识别一
    ios开发事件处理之 四:hittest方法的底层实现与应用
    ios开发事件处理之:三 :寻找最合适的view
    ios开发事件处理之 :二:事件的产生与传递
    ios开发事件处理之:一:UIView的拖拽
    ios开发transform属性
  • 原文地址:https://www.cnblogs.com/moguwang/p/5304375.html
Copyright © 2020-2023  润新知