A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 李泽霖 黑马帝   /  2012-2-10 12:53  /  1942 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

有几种排序,哪个效率更高些,请分别说明下

评分

参与人数 1技术分 +1 收起 理由
唐秀启 + 1 请把求助改成已解决 谢谢合作

查看全部评分

5 个回复

倒序浏览
排序方法一般都就那几种。像冒泡排序,直接插入排序,快速排序,简单选择排序,希尔排序,堆排序。其排序介绍自己看吧。
1、冒泡排序属于稳定排序,是一种借助“交换”进行排序的方法。首先要将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序,则将两个记录交换之,然后比较第二个记录与第三个记录的关键字,以此类推,直至第n-1个记录与第n个记录的关键字进行比较为止,这一过程称为第一趟冒泡排序,其结果使得关键字最大的记录被安置在最后一个记录的位置上;然后进行第二趟冒泡排序,对前N-1个记录进行同样操作;以此类推,直到在一趟排序过程中没有进行过交换记录的操作为止。
2、直接插入排序属于稳定的排序,每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。第一趟将待比较的数值与它的前一个数值进行比较,当前一数值比待比较数值大的情况下继续循环比较,依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程,结束该次循环。
3、快速排序属于不稳定排序,是对起泡排序的一种改进。它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。假设待排序的序列为{R.[s],R.[s+1],…….,R.[t]},首先任意选取一个记录,然后按下述原则从新排序记录:将关键字较他小的记录都安置在他的位置之前,将所有关键字较他大的记录都安置在他的位置后面。由此可以该“枢轴”记录最后所落的位置i作为分界线,将序列{R[s],R[s+1]…….R[t]}分割成两个子序列{R[s],R[s+1]…..R[i-1]}和{R[i+1]……R[t]},这个过程称作一趟快速排序。一趟快速排序的具体做法是:附设两个指针low和high,它们的初值分别指向数组第一个数据和最后一个数据,将枢轴记录暂存在R[0]的位置上排序过程中只作R[low]或R[high]的单向移动,直至一趟排序结束后再将枢轴记录移至正确位置上。
4、简单选择排序属于不稳定排序,基本思想是,每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。第i趟简单选择排序是指通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录进行交换。共需进行n-1趟比较,直到所有记录排序完成为止。例如:进行第i趟选择时,从当前候选记录中选出关键字最小的k号记录,并和第i个记录进行交换。
5、希尔排序属于不稳定排序,也是一种属插入排序类,它的基本思想是:先将整个待排记录序列分割称为若干个子序列分别进行直接插入排序,待整个序列中记录“基本有序”时,再对全体记录进行一次直接插入排序。希尔排序的一个特点是:子序列的构成不是简单的“逐段分割”,而是将相隔某个“增量”的记录组成一个子序列。
6、堆排序属于不稳定排序,它的基本思想是,先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区,再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key;由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆,然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n- 2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。直到无序区只有一个元素为止。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
网上关于排序讲的很好,也很详细,还有代码演示:
public class Sort {
          public void swap(int a[], int i, int j) {
            int tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
          }
          public int partition(int a[], int low, int high) {
            int pivot, p_pos, i;
            p_pos = low;
            pivot = a[p_pos];
            for (i = low + 1; i <= high; i++) {
              if (a[i] > pivot) {
                p_pos++;
                swap(a, p_pos, i);
              }
            }
            swap(a, low, p_pos);
            return p_pos;
          }
          public void quicksort(int a[], int low, int high) {
            int pivot;
            if (low < high) {
              pivot = partition(a, low, high);
              quicksort(a, low, pivot - 1);
              quicksort(a, pivot + 1, high);
            }
          }
          public static void main(String args[]) {
            int vec[] = new int[] { 37, 47, 23, -5, 19, 56 };
            int temp;
            //选择排序法(Selection Sort)
            long begin = System.currentTimeMillis();
            for (int k = 0; k < 1000000; k++) {
              for (int i = 0; i < vec.length; i++) {
                for (int j = i; j < vec.length; j++) {
                  if (vec[j] > vec[i]) {
                    temp = vec[i];
                    vec[i] = vec[j];
                    vec[j] = temp;
                  }
                }
              }
            }
            long end = System.currentTimeMillis();
            System.out.println("选择法用时为:" + (end - begin));
            //打印排序好的结果
            for (int i = 0; i < vec.length; i++) {
              System.out.println(vec[i]);
            }
            //  冒泡排序法(Bubble Sort)
            begin = System.currentTimeMillis();
            for (int k = 0; k < 1000000; k++) {
              for (int i = 0; i < vec.length; i++) {
                for (int j = i; j < vec.length - 1; j++) {
                  if (vec[j + 1] > vec[j]) {
                    temp = vec[j + 1];
                    vec[j + 1] = vec[j];
                    vec[j] = temp;
                  }
                }
              }
            }
            end = System.currentTimeMillis();
            System.out.println("冒泡法用时为:" + (end - begin));
            //打印排序好的结果
            for (int i = 0; i < vec.length; i++) {
              System.out.println(vec[i]);
            }
            //插入排序法(Insertion Sort)
            begin = System.currentTimeMillis();
            for (int k = 0; k < 1000000; k++) {
              for (int i = 1; i < vec.length; i++) {
                int j = i;
                while (vec[j - 1] < vec[i]) {
                  vec[j] = vec[j - 1];
                  j--;
                  if (j <= 0) {
                    break;
                  }
                }
                vec[j] = vec[i];
              }
            }
            end = System.currentTimeMillis();
            System.out.println("插入法用时为:" + (end - begin));
            //打印排序好的结果
            for (int i = 0; i < vec.length; i++) {
              System.out.println(vec[i]);
            }
            //快速排序法(Quick Sort)
            Sort s = new Sort();
            begin = System.currentTimeMillis();
            for (int k = 0; k < 1000000; k++) {
              s.quicksort(vec, 0, 5);
            }
            end = System.currentTimeMillis();
            System.out.println("快速法用时为:" + (end - begin));
            //打印排序好的结果
            for (int i = 0; i < vec.length; i++) {
              System.out.println(vec[i]);
            }
          }
        }
运行结果:选择法用时为:94
56
47
37
23
19
-5
冒泡法用时为:47
56
47
37
23
19
-5
插入法用时为:16
56
47
37
23
19
-5
快速法用时为:78
56
47
37
23
19
-5
如果我们要是存储的对象,比如在ArrayList集合中存储的一系列对象进行排序能必须使用实现了Comparator接口的对象,而要排序则使用的  Collections 静态方法sort()方法。

评分

参与人数 1技术分 +2 收起 理由
admin + 2

查看全部评分

回复 使用道具 举报
快速排序(Quicksort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。快速排序不稳定,O(log(n))的额外空间,时间复杂度为O(nlog(n)),不是自适应的。

快速排序(Quicksort)有几个值得一提的变种算法,这里进行一些简要介绍:

随机化快排:快速排序的最坏情况基于每次划分对主元的选择。基本的快速排序选取第一个元素作为主元。这样在数组已经有序的情况下,每次划分将得到最坏的结果。一种比较常见的优化方法是随机化算法,即随机选取一个元素作为主元。这种情况下虽然最坏情况仍然是O(n^2),但最坏情况不再依赖于输入数据,而是由于随机函数取值不佳。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。一位前辈做出了一个精辟的总结:“随机化快速排序可以满足一个人一辈子的人品需求。”

随机化快速排序的唯一缺点在于,一旦输入数据中有很多的相同数据,随机化的效果将直接减弱。对于极限情况,即对于n个相同的数排序,随机化快速排序的时间复杂度将毫无疑问的降低到O(n^2)。解决方法是用一种方法进行扫描,使没有交换的情况下主元保留在原位置。

平衡快排(Balanced Quicksort):每次尽可能地选择一个能够代表中值的元素作为关键数据,然后遵循普通快排的原则进行比较、替换和递归。通常来说,选择这个数据的方法是取开头、结尾、中间3个数据,通过比较选出其中的中值。取这3个值的好处是在实际问题(例如信息学竞赛……)中,出现近似顺序数据或逆序数据的概率较大,此时中间数据必然成为中值,而也是事实上的近似中值。万一遇到正好中间大两边小(或反之)的数据,取的值都接近最值,那么由于至少能将两部分分开,实际效率也会有2倍左右的增加,而且利于将数据略微打乱,破坏退化的结构。

外部快排(External Quicksort):与普通快排不同的是,关键数据是一段buffer,首先将之前和之后的M/2个元素读入buffer并对该buffer中的这些元素进行排序,然后从被排序数组的开头(或者结尾)读入下一个元素,假如这个元素小于buffer中最小的元素,把它写到最开头的空位上;假如这个元素大于buffer中最大的元素,则写到最后的空位上;否则把buffer中最大或者最小的元素写入数组,并把这个元素放在buffer里。保持最大值低于这些关键数据,最小值高于这些关键数据,从而避免对已经有序的中间的数据进行重排。完成后,数组的中间空位必然空出,把这个buffer写入数组中间空位。然后递归地对外部更小的部分,循环地对其他部分进行排序。

三路基数快排(Three-way Radix Quicksort,也称作Multikey Quicksort、Multi-key Quicksort):结合了基数排序(radix sort,如一般的字符串比较排序就是基数排序)和快排的特点,是字符串排序中比较高效的算法。该算法被排序数组的元素具有一个特点,即multikey,如一个字符串,每个字母可以看作是一个key。算法每次在被排序数组中任意选择一个元素作为关键数据,首先仅考虑这个元素的第一个key(字母),然后把其他元素通过key的比较分成小于、等于、大于关键数据的三个部分。然后递归地基于这一个key位置对“小于”和“大于”部分进行排序,基于下一个key对“等于”部分进行排序。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
稳定的排序方法有 冒泡排序,直接插入排序,归并排序
不稳定的排序方法有 快速排序,直接选择排序,堆排序,希尔排序
排序算法平均性能最好的是 快速排序,但是当原序列基本有序的时候 冒泡排序退化为直接插入排序。
没有最好的排序算法,具体问题具体分析。
堆排序占用1个空间,快速排序需要 lgn个空间,归并排序需要n个辅助空间。
算法要结合辅助空间和消耗的时间进行评估。一般考虑消耗的时间。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
在数据结构中比较快的两种排序,归并和快速排序,基本两者速度差不多,此外希尔排序也还比较快,其他比如说选择、冒泡、插入等相对比较慢,但是思路简单。

评分

参与人数 1技术分 +1 收起 理由
admin + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马