一插入排序
1 直接插入排序
直接插入排序是一种简单的插入排序法,其基本思路是:把待排序的记录按其关键字的大小逐个插入到一个已经排序好的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。
public class InsertSort {
public static void main(String[] args) {
insertSort();
}
// 将数列分为有序和无序两个部分,每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,
private static void insertSort() {
int a[]=new int[]{49,38,65,97,76,13,27,78,2};
int temp=0;
for(int i=1;i0;j--){
if(a[j]<a[j-1]){
temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
}
}
}
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
分析算法:为了正确插入第i个记录,最多比较i次,最少比较1次,平均比较i/2次,从i=1到n-1的i/2的求和 约等于n^2,所以时间复杂度为O(n^2a) 空间复杂度为只需一个记录单元的辅助空间 O(1)。
2 希尔排序
希尔排序又称之为“缩小增量排序” 基本思路是:选的第一个增量d1<n,把全部记录按照此值从第一个记录起进行分组,所以相距为d1的记录为一组。先在各组内进行插入排序,然后减小间隔取第二个增量,d2<d1直到di=1为止。
public class ShellSort {
public static void main(String[] args) {
shellSort();
}
private static void shellSort() {
int temp=0;
int k;
int a[]={1,54,6,3,78,34,12,45,56,100};
for(int i=a.length/2;i>=1;i/=2){
for(int j=i;j=0&&temp<a[k]){
a[j]=a[k];
a[k]=temp;
}
}
}
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}empty
分析算法:d较大时 ,被移动的记录是跳跃式践行的 到最后一趟时,不需要移动太多,平均移动次数是n^1.3 希尔排序是一种不稳定的排序
二 交换排序
1 冒泡排序
冒泡排序也称起泡排序,通过相邻的记录两两比较交换,使关键字较小的记录像水中的气泡一样逐趟向上漂浮,关键字大的往下沉。
基本思路:先将第一个记录的关键字和第二个进行比较,若为逆序,则交换位置,然后第二个再和第三个比较,如此下去,直到n个记录和n-1个记录的关键字进行比较完为止,这样就完成了第一趟冒泡排序,关键字最大的数安置在n的位置,然后进行第二趟排序,其结果是关键字最大的数放在n-1位置上,对n个记录的文件需要进行n-1次趟冒泡排序。
public class BubbleSort {
public static void main(String[] args) {
bubbleSort();
}
private static void bubbleSort() {
int temp;
int a[]={9,7,1,6,4,8,3,2,5};
for(int i=0;i<a.length-1;i++){
for(int j=0;ja[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for(int i=0;i<a.length;i++)
System.out.print(a[i]+" ");
}
}
算法分析:时间复杂度O(n^2)
2 快速排序
快速排序是对冒泡排序的一种改进,快速排序的基本思想:在待排序的n个记录中任选一个记录,通常去取第一个记录,以该记录的关键字值为基准,用交换的方法将所有记录分为两部分,所有关键字比它小的记录均排在前面,关键字大的均排在它之后,这样就完成了一趟排序,然后对所分的前后两部分分别重复上面的操作,直到每部分内只有一个记录为止,排序结束。
public class QuickSort {
public static void main(String[] args) {
quickSort();
}
private static void quickSort() {
int a[]={52,68,79,34,28,35,64,79,12};
quick(a);
for(int i=0;i<a.length;i++){
System.out.println(a[i]+" ");
}
}
private static int getMiddle(int[] a, int low, int high) {
int temp=a[low];//数组中第一个数作为中轴
while(low<high){
while(low
=temp){
high--;
}
a[low]=a[high];//比中轴小的记录移到最低端
while(low<high&&a[low]<=temp){
low++;
}
a[high]=a[low];
}
a[low]=temp;
return low;
}
private static void quick_sort(int[] a, int low, int high) {
if(low
0){//查看数组是否为空
quick_sort(a,0,a.length-1);
}
}
}
三 选择排序
1 简单选择排序
选择排序是指每次从待排序的记录中选出关键字小的记录,顺序放在已排序的有序序列中,基本思想:对待排序文件进行n-1趟扫描,每次扫面选出最小值与第一个位置的数交换,依次类推 ,直到最后一个数和倒数第二个数
public class SelectSort {
public static void main(String[] args) {
sort();
}
private static void sort() {
int a[]={24,36,12,56,75,4,19,2};
int value,index;//最小元素 与最下的下标
for(int i=0;i<a.length;i++){
value=a[i];
index=i;
//选择最小的元素及最小的下标
for(int j=i;j<a.length;j++){
if(a[j]<value){
value=a[j];
index=j;
}
}
//找到的那个最小元素然后处理
if(value!=a[i]&&index!=i){
a[index]=a[i];
a[i]=value;
}
}
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
}
算法分析:时间复杂度O(n^2)
2 堆排序
堆排序是简单选择排序的改进,因为简单选择排序需要第一次做n-1次比较,然后n-2次比较...所以为了避免重复的比较。可以采用树形选择排序
基本思路:对一组待排序的记录序列,先将其关键字按堆得定义排列成一个序列(称初建堆),找到了最大最小关键字,将其取出,用剩余的n-1个元素在重建堆,便可找到最小最大值,直到排序完成。
public class HeapSort {
public static void main(String[] args) {
int a[]={2,1,4,6,3,7,5,89,98,56,57};
heap_sort(a,11);//建堆 最大值放在根节点
for(int i=0;i<11;i++){
System.out.print(a[i]+" ");
}
}
public static void heapfy(int a[],int i,int size){
if(i<size){
int left=i*2+1;//左节点
int right=i*2+2;//右节点
int largest=i;//根节点
if(left<size){
if(a[largest]<a[left]){//判断左节点跟根节点大小
largest=left;
}
}
if(right
a[largest]){//判断右节点个跟根节点大小
largest=right;
}
}
if(largest!=i){
int temp=a[largest];
a[largest]=a[i];
a[i]=temp;
heapfy(a,largest,size);//递归建堆
}
}
}
public static void max_heapfy(int a[],int size){
for(int i=size-1;i>=0;i--){
heapfy(a,i,size);
}
}
public static void heap_sort(int a[],int size){
for(int i=size-1;i>=0;i--){//堆排序
max_heapfy(a,i+1);
int temp=a[0];
a[0]=a[i];
a[i]=temp;
}
}
}
四 归并排序
归并排序是另一种类型的排序方法,归并就是把两个或者两个或者多个有序表进行并合,得到新的有序表,将两个有序子文件合并成一个有序文件成为二路归并。当然,也有三路归并或者多路归并。基本思想:归并 分治 归并的基本思想是比较各个有序表的第一个记录的关键字的值,找出最小的第一个作为排序后的第一个记录的值 ,取出这个记录存入表中 ,依次类推,
public class MergingSort {
public static void main(String[] args) {
int a[]={12,36,57,68,2,56,34,51,54,75,98,66,32};
int b[]=new int[13];
MergeSort(a,0,12,b);
for(int i=0;i<13;i++){
System.out.println(a[i]+" ");
}
}
//归并排序的核心工作
public static void MergeSort(int a[],int left,int right,int temp[]){
if(left<right){
int mid=left+(right-left)/2;
//归并排序 使左边有序
MergeSort(a,left,mid,temp);
//归并排序 使右边有序
MergeSort(a,mid+1,right,temp);
//合并两个有序序列
Mergearry(a,left,mid,right,temp);
}
}
public static void Mergearry(int a[],int left,int mid,int right,int temp[]){
int i=left,j=mid+1;
int m=mid,n=right;
int k=0;
//二路归并
while(i<=m&&j<=n){
//将小的值放入临时数组中
if(a[i]<=a[j])
temp[k++]=a[i++];
else
temp[k++]=a[j++];
}
//处理子数组中的剩余元素
while(i<=m)
temp[k++]=a[i++];
while(j<=n)
temp[k++]=a[j++];
//从临时书中中拷贝到目标数组中
for(i=0;i<k;i++)
a[left+i]=temp[i];
}
}
五 基数排序
基数排序是和前面几种排序完全不同的一种排序方式。基数排序不需要进行关键字比较,而是各位值比较,根据优先位进行比较 。
基本思想: 把待比较值 设为统一的数位长度 数位短的前面补零,然后 从最低位各位开始依次进行排序 任何比较十位 最后比较最高位 然后数列变为一个有序序列
public class RadixSort {
public static void main(String[] args) {
int []a=new int[]{75,52, 34 ,63,54,89,65,66,23,32,32,45,28,12,1,14,15,37,38,44,46,82,29};
radixSort(a,100);
for(int num:a){
System.out.println(num);
}
}
private static void radixSort(int[] a, int d) {
int n=1;//代表位数对应的数
int k=0;//保存每一位排序后的结果用于下一位的排序输入
int length=a.length;
int[][] bucket=new int[10][length];//排序桶用于保存每次排序后的结果 这一位上排序相同的数字放在同一个桶里面
int[] order=new int[length];//用于保存每个桶里面有多少个数字
while(n<d){
for(int num:a){//将数组a里的每个数字放在相应的桶里面
int digit=(num/n)%10;//第一次是算出个位
bucket[digit][order[digit]]=num;
order[digit]++;//order[weishi是几 ]任何对应几个
}
for(int i=0;i<a.length;i++){///将前一个循环生产的桶里的数据覆盖到与数组中用于保存这一位的排序结果
if(order[i]!=0){//遍历桶里面的元素保存到原数组中
for(int j=0;j<order[i];j++){
a[k]=bucket[i][j];
k++;
}
}
order[i]=0;//清除数据 用于下一次排序
}
n*=10;
k=0;//将k置于零 用于保存下一轮的排序
}
}
}
结论:
1 从平均时间上来说快速排序最快 但在最坏情况下不如堆排序跟归并排序。
2 从算法简单性看,不如选择排序 插入排序
3 从稳定性上看 直接插入排序 冒泡排序 和归并排序 是稳定的 而希尔排序 直接选择排序 快速排序 堆排序 是不稳定的
4 从待排序的记录数n的大小看 n小时 采用简单排序 n大时 采用改进排序