java排序算法

来源:互联网 发布:鬼遮眼网络大电影 编辑:程序博客网 时间:2024/06/15 15:12
对于有n个结点的线性表(e0,e1,…,en-1),将结点中某些数据项的值按递增或递减的次序,重新排列线性表结点的过程,称为排序。排序时参照的数据项称为排序码,通常选择结点的键值作为排序码。

若线性表中排序码相等的结点经某种排序方法进行排序后,仍能保持它们在排序之前的相对次序,称这种排序方法是稳定的;否则,称这种排序方法是不稳定的。

在排序过程中,线性表的全部结点都在内存,并在内存中调整它们在线性表中的存储顺序,称为内排序。在排序过程中,线性表只有部分结点被调入内存,并借助内存调整结点在外存中的存放顺序的排序方法成为外排序。

下面通过一个表格简单介绍几种常见的内排序方法,以及比较一下它们之间的性能特点。

 

排序方法
 简介
 平均时间
 最坏情况
 辅助存储
 是否稳定
 
简单排序
 选择排序
 反复从还未排好序的那部分线性表中选出键值最小的结点,并按从线性表中选出的顺序排列结点,重新组成线性表。直至未排序的那部分为空,则重新形成的线性表是一个有序的线性表。
 O( )
 O( )
 O(1)
 不稳定
 
直接插入排序
 假设线性表的前面I个结点序列e0,e1,…,en-1是已排序的。对结点在这有序结点ei序列中找插入位置,并将ei插入,而使i+1个结点序列e0,e1,…,ei也变成排序的。依次对i=1,2,…,n-1分别执行这样的插入步骤,最终实现线性表的排序。
 O( )
 O( )
 O(1)
 稳定
 
冒泡排序
 对当前还未排好序的范围内的全部结点,自上而下对相邻的两个结点依次进行比较和调整,让键值大的结点往下沉,键值小的结点往上冒。即,每当两相邻比较后发现它们的排列顺序与排序要求相反时,就将它们互换。
 O( )
 O( )
 O(1)
 稳定
 
希尔排序
 对直接插入排序一种改进,又称“缩小增量排序”。先将整个待排序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
 kn ln n
 O( )
 O(logn)
 不稳定
 
快速排序
 对冒泡排序的一种本质的改进。通过一趟扫视后,使待排序序列的长度能大幅度的减少。在一趟扫视后,使某个结点移到中间的正确位置,并使在它左边序列的结点的键值都比它的小,而它右边序列的结点的键值都不比它的小。称这样一次扫视为“划分”。每次划分使一个长序列变成两个新的较小子序列,对这两个小的子序列分别作同样的划分,直至新的子序列的长度为1使才不再划分。当所有子序列长度都为1时,序列已是排好序的了。
 O(nlogn)
 O( )
 O(logn)
 不稳定
 
堆排序
 一种树形选择排序,是对直接选择排序的有效改进。一个堆是这样一棵顺序存储的二叉树,它的所有父结点(e[i])的键值均不小于它的左子结点(e[2*i+1])和右子结点(e[2*i+2])的键值。初始时,若把待排序序列的n个结点看作是一棵顺序存储的二叉树,调整它们的存储顺序,使之成为一个堆,这时堆的根结点键值是最大者。然后将根结点与堆的最后一个结点交换,并对少了一个结点后的n-1结点重新作调整,使之再次成为堆。这样,在根结点得到结点序列键值次最大值。依次类推,直到只有两个结点的堆,并对它们作交换,最后得到有序的n个结点序列。
 O(nlogn)
 O(nlogn)
 O(1)
 不稳定
 
归并排序
 将两个或两个以上的有序子表合并成一个新的有序表。对于两个有序子表合并一个有序表的两路合并排序来说,初始时,把含n个结点的待排序序列看作有n个长度都为1的有序子表所组成,将它们依次两两合并得到长度为2的若干有序子表,再对它们作两两合并……直到得到长度为n的有序表,排序即告完成。
 O(nlogn)
 O(nlogn)
 O(n)
 稳定
 

 

后面根据各种排序算法,给出了C语言的实现,大家在复习的时候可以做下参考。

u       选择排序

void ss_sort(int e[], int n)

{     int i, j, k, t;

       for(i=0; i< n-1; i++) {

              for(k=i, j=i+1; j<n; j++)

                     if(e[k]>e[j]) k=j;

              if(k!=i) {

                     t=e[i]; e[i]=e[k]; e[k]=t;

              }

       }

}

u       直接插入排序

void si_sort(int e[], int n)

{     int i, j, t;

       for(i=0; i< n; i++) {

              for(t=e[i], j=i-1; j>=0&&t<e[j]; j--)

                     e[j+1]=e[j];

              e[j+1]=t;

       }

}

u       冒泡排序

void sb_sort(int e[], int n)

{     int j, p, h, t;

       for(h=n-1; h>0; h=p) {

              for(p=j=0; j<h; j++)

                     if(e[j]>e[j+1]) {

                            t=e[j]; e[j]=e[j+1]; e[j+1]=t;

                            p=j;

              }

       }

}

u       希尔排序

void shell(int e[], int n)

{     int j, k, h, y;

       for(h=n/2; h>0; h=h/2) 

              for(j=h; j<n; j++) {

                     y=e[j];

                     for(k=j-h; k>0&&y<e[k]; k-=h)

                            e[k+h]=e[k];

                     e[k+h]=y;

       }

}

u       堆排序

void sift(e, n, s)

int e[];

int n;

int s;

{     int t, k, j;

       t=e[s];

                     k=s; j=2*k+1;

                     while(j<n) {

                            if(j<n-1&&e[j]<e[j+1])

                                   j++;

                            if(t<e[j]) {

                                   e[k]=e[j];

                                   k=j;

                                   j=2*k+1;

                            }else break;

                     }

                     e[k]=t;

              }

 

              void heapsorp (int e[], int n)

              {     int i, k, t;

                     for(i=n/2-1; i>=0; i--)

                            sift(e, n, i);

                     for(k=n-1; k>=1; k--) {

                            t=e[0]; e[0]=e[k]; e[k]=t;

                            sift(e, k, 0);

                     }

              }

u       快速排序

void r_quick(int e[], int low, int high)

       {     int i, j, t;

              if(low<high) {

                     i=low; j=high; t=e[low];

                     while(i<j) {

                            while (i<j&&e[j]>t) j--;

                            if(i<j) e[I++]=e[j];

                            while (i<j&&e[i]<=t) i++;

                            if(I<j) e[j--]=e[i];

                     }

              e[i]=t;

              r_quick(e,low,i-1);

              r_quick(w,i+1,high);

              }

       }

另外,外排序是对大型文件的排序,待排序的记录存储在外存中,在排序过程中,内存只存储文件的一部分记录,整个排序过程需进行多次的内外存间的交换。


***  查找


查找就是在按某种数据结构形式存储的数据集合中,找出满足指定条件的结点。

按查找的条件分类,有按结点的关键码查找、关键码以外的其他数据项查找或其他数据项的组合查找等。按查找数据在内存或外存,分内存查找和外存查找。按查找目的,查找如果只是为了确定指定条件的结点存在与否,成为静态查找;查找是为确定结点的插入位置或为了删除找到的结点,称为动态查找。

这里简单介绍几种常见的查找方法。

u       顺序存储线性表的查找

这是最常见的查找方式。结点集合按线性表组织,采用顺序存储方式,结点只含关键码,并且是整数。如果线性表无序,则采用顺序查找,即从线性表的一端开始逐一查找。而如果线性表有序,则可以使用顺序查找、二分法查找或插值查找。

u       分块查找

分块查找的过程分两步,先用二分法在索引表中查索引项,确定要查的结点在哪一块。然后,再在相应块内顺序查找。

u       链接存储线性表的查找

对于链接存储线性表的查找只能从链表的首结点开始顺序查找。同样对于无序的链表和有序的链表查找方法不同。

u       散列表的查找

散列表又称杂凑表,是一种非常实用的查找技术。它的原理是在结点的存储位置和它的关键码间建立一个确定的关系,从而让查找码直接利用这个关系确定结点的位置。其技术的关键在于解决两个问题。

I.          找一个好的散列函数

II.       设计有效解决冲突的方法

常见的散列函数有:

I.          质数除取余法

II.       基数转换法

III.     平方取中法

IV.     折叠法

V.        移位法

常见的解决冲突的方法有:

I.          线性探查法

II.       双散列函数法

III.     拉链法

原创粉丝点击