排序的几种常见方法:
定义一个顺序表结构 :
#define MAXSIZE 10000 //用于要排序数组个数最大值,可根据需要修改
typedef struct
{
int r[MAXSIZE+1]; //用于存储要排序数组,r[0]用作哨兵或临时变量
int length; //用于记录顺序表的长度
}SqList;
1.简单排序
思路:让第一个位置元素都和它后面位置的元素逐个比较,如果大则交换,这样第一位置的元素在一次循环后一定变为最小值,然后让第二个位置的元素都和它后面位置的元素逐个比较,如果大则交换,这样出次最小值放到第二个位置,依次下去进行排序,如下图:
代码实现:
void BubbleSort0(SqList *L)
{
int i,j;
for(i=1;ilength;i++) //有L->lenght个元素,要比较L->lenght次
{
for(j=i+1;j<=L->length;j++) //让第i个元素依次同它后面的元素比较,把最小值放到第i个位置
{
if(L->r[i]>L->r[j])
swap(L,i,j);
}
}
}
方法的优缺点 :优点是简单,缺点在排序好1和2的位置后,对其余关键字的排序没有什么帮助(数字3还被换到的最后一位),效率差.
2.冒泡排序法:
刚刚的简单排序是从第i个元素开始逐个与下面的元素比较,选出(length+1-i)个元素中的最小值放在第i个元素的位置.而冒泡排序的基本思想是两两比较相邻记录的元素,如果反序则交换,直到没有反序为止,第一次循环如下图:
代码实现:
void BubbleSort(SqList *L)
{
int i,j;
for(i=1;ilength;i++) //比较L->length-1次
{
for(j=L->length-1;j>=i;j--) //从下面的两个元素开始比较
{
if(L->r[j]>L->r[j+1]) //如果前者大于后者就交换(小的往上冒)
swap(L,j,j+1);
}
}
}
优缺点:在不断循环过程中,除了将元素1放到第一个的位置,我们还将元素2从第九位置提高了第三位置,显然比简单排序进步,缺点这边固定循环Length-1次,如果在第
3.改进的冒泡排序
思想:设置一个标志,如果发现序列已经有序就退出循环.
代码实现:
void BubbleSort2(SqList *L)
{
int i,j;
Status flag=TRUE;
for(i=1;ilength&&flag;i++) //增加了标志,如果下面没有执行交换,就认为已经有序,for循环停止
{
flag = FALSE;
for(j=L->length-1;j>=i;j--)
{
if(L->r[j]>L->r[j+1])
{
swap(L,j,j+1);
flag=TRUE; //如果执行了交换,就将标志设置为TRUE
}
}
}
}
4.选择排序
基本思想:将第一个元素逐个与后面的元素比较,记录下最小值的下标,将最小值与第一个元素交换,再将第二个元素逐个与后面的元素比较,记录下最小值的下标,将比较中的最小值与第二个元素交换,以此类推。
代码实现:
void SelectSort(SqList *L)
{
int i,j,min;
for(i=1;ilength;i++) //比较L->length-1次
{
min = i; //min用来记录每一轮比较中最小值的下标
for(j=i+1;j<=L->length;j++)
{
if(L->r[min]>L->r[j])
{
min = j;
}
}
if(min!=i) //每一轮循环后,与将记录的最小值交换
swap(L,i,min);
}
}
5.归并排序
归并排序使用了分治的思想,要将一个数组排序,可以将它分为两半分别排序,然后将结果归并成一个排序好的数组。
//自顶向下的归并排序
class PaiXu
{
static int[] aux;
public static void sort(int[] a)
{
aux = new int[a.length];
sort(a,0,a.length-1);
}
//分治的思想
public static void sort(int[] a,int low,int high){
if(lowmid) a[k] = aux[j++];
else if(j>high) a[k] = aux[i++];
else if(aux[i]>aux[j]) a[k] = aux[j++];
else a[k] = aux[i++];
}
}
public static void main(String[] args)
{
int[] a= {90,50,10,90,30,70,40,10,80,60,20,10,70,37,5,2,1,9,43,23,11,44,1,1,90};
sort(a);
System.out.println(Arrays.toString(a));
}
}
快速排序:
public void sort(int[] a)
{
int N = a.length-1;
Qsort(a,0,N);
}
//典型的分治思想
public void Qsort(int[] a,int low,int high)
{
if(low=a[low])
j--;
while(i=j) //最终是i==j停下来,这一点要记住
break;
exch1(a,i,j);
}
exch1(a,low,i);
return j;
}
优先队列:
许多应用需要处理有序的元素,但不一定要求它们全部有序,或是不一定要一次就将它们排序。很多情况下我们收集一些元素,处理当前最大的元素,然后在收集更多的元素,在处理当前最大的元素,然后在收集更多的元素,再处理当前的最大的元素。一种合适的数据结构支持这两种操作:删除最大的元素和插入元素。
使用到的两个操作:
上浮:上浮指的是将大的结点上浮(插入元素时用到了上浮)
下沉:下沉指的是将大的结点小的下沉(删除元素时用到了下沉)
两个都可以用来构建一个大顶堆。在优先队列中,对数组来说插入一个元素都是插入在数组尾部,此时使用上浮可以构建大顶堆。
优先队列的的操作的过程:
插入一个元素:向数组尾部插入一个元素,通过上浮将大的值上浮到堆顶,构建大顶堆
删除一个元素:将第一个元素取出放到临时变量中(这是这堆数中最大的一个数),然后将第一个元素和最后一个元素交换,并将最后一个数的位置设置为null即删除最后一个元素,此时第一个元素并不是最大值,也就是说现在构成的堆也不是大顶堆,此时对第一个元素进行下沉操作,通过下沉构建大顶堆。
记忆中用到的地方:阻塞队列中,PriprityBlockingQueue中用到。