一、排序
排序:将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序。
排序也是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。
1.常见的排序算法
常见的排序算法有:快速排序、希尔排序、堆排序、直接选择排序不是稳定的排序算法,而基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法。
其中,直接插入排序和希尔排序属于插入排序;直接选择排序和堆排序属于选择排序;冒泡排序和快速排序属于交换排序。这些都属于内排序。
什么是稳定排序呢?
假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法是稳定的。
1)冒泡排序
相邻的两个元素进行比较,如果符合条件换位。
特点:第一圈,最值出现在最后位。
优点:稳定。
缺点:慢,效率低,每次只能移动相邻两个数据。
示例:
- <pre class="java" name="code">//冒泡排序
- public static void bubbleSort(int[] arr)
- {
- for(int x=0;x<arr.length-1;x++)//外循环控制比较次数
- {
- for(int y=0;y<arr.length-x-1;y++)//-x:让每一次比较的元素减少;-1:避免角标越界
- {
- if(arr[y]>arr[y+1])
- {
- int temp=arr[y];
- arr[y]=arr[y+1];
- arr[y+1]=temp;
- }
- }
- }
- }
- //对数组的输出进行了封装
- public static void printArray(int[] arr)
- {
- System.out.print("[");
- for(int x=0;x<arr.length;x++)//遍历数组
- {
- if(x!=arr.length-1)//如果不是数组中最后一个值
- {
- System.out.print(arr[x]+",");
- }else{
- System.out.println(arr[x]+"]");
- }
- }
- }
- public static void main(String[] args)
- {
- int[] arr={2,7,9,6,5,4,55,41};
- //排序前
- printArray(arr);
- //进行排序
- bubbleSort(arr);
- //排序后
- printArray(arr);
- }
2)选择排序
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
也就是先拿0角标位置与其他角标依次比较,最小的到0角标位置,在拿1角标位置与其他角标依次比较(0角标除外),最小的到1角标位置,以此类推比较。
特点:内循环结束一次,最值出现头角标位置上。
优点:移动数据的次数已知(n-1次);
缺点:比较次数多,不稳定。
示例:
- //选择排序
- public static void selectSort(int[] arr)
- {
- for(int x=0;x<arr.length-1;x++)
- {
- for(int y=x+1;y<arr.length;y++)
- {
- if(arr[x]>arr[y])
- {
- //对位置进行置换
- int temp=arr[x];//定义一个临时容器
- arr[x]=arr[y];
- arr[y]=temp;
- }
- }
- }
- }
- //输出数组方法
- public static void printArray(int[] arr)
- {
- System.out.print("[");
- for(int x=0;x<arr.length;x++)
- {
- if(x!=arr.length-1)
- {
- System.out.print(arr[x]+",");
- }else
- {
- System.out.println(arr[x]+"]");
- }
- }
- }
- public static void main(String[] args)
- {
- int[] arr={2,4,6,3,7,8,9};
- //排序前
- printArray(arr);
- //进行排序
- selectSort(arr);
- //排序后
- printArray(arr);
- }
3)插入排序
插入排序:已知一组升序排列数据a[1]、a[2]、……a[n],一组无序数据b[1]、b[2]、……b[m],需将二者合并成一个升序数列。首先比较b[1]与a[1]的值,若b[1]大于a[1],则跳过,比较b[1]与a[2]的值,若b[1]仍然大于a[2],则继续跳过,直到b[1]小于a数组中某一数据a[x],则将a[x]~a[n]分别向后移动一位,将b[1]插入到原来a[x]的位置这就完成了b[1]的插入。b[2]~b[m]用相同方法插入。(若无数组a,可将b[1]当作n=1的数组a)
优点:稳定,快。
缺点:比较次数不一定,比较次数越多,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决这个问题。
图例:
示例:
- //插入排序
- public static void insertionSort(int[] arr)
- {
- for(int x=1;x<arr.length;x++)
- {
- for(int y=x;(y>0)&&(arr[y]<arr[y-1]);y--)
- {
- int temp=arr[y];
- arr[y]=arr[y-1];
- arr[y-1]=temp;
- }
- }
- }
- public static void printArray(int[] arr)
- {
- System.out.print("[");
- for(int x=0;x<arr.length;x++)
- {
- if(x!=arr.length-1)
- {
- System.out.print(arr[x]+",");
- }else{
- System.out.println(arr[x]+"]");
- }
- }
- }
- public static void main(String[] args)
- {
- int[] arr={1, 3, 2, 5, 12, 123, 23, 2, 541, 1, 76, 76};
- //排序前
- printArray(arr);
- //进行排序
- insertionSort(arr);
- //排序后
- printArray(arr);
- }
4)希尔排序
希尔排序(Shell Sort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩小增量排序。
原理:
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。发现当n不大时,插入排序的效果很好。首先取一增量d(d<n),将a[1]、a[1+d]、a[1+2d]……列为第一组,a[2]、a[2+d]、a[2+2d]……列为第二组……,a[d]、a[2d]、a[3d]……列为最后一组以次类推,在各组内用插入排序,然后取d'<d,重复上述操作,直到d=1。
优点:快,数据移动少。
缺点:不稳定,d的取值是多少,应取多少个不同的值,都无法确切知道,只能凭经验来取。
注意:排序中希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏 的情况下执行的效率会非常差。
示例:
- public static int[] a = { 10, 32, 1, 9, 5, 7, 12, 0, 4, 3 };
- public static void main(String args[]) {
- int i; // 循环计数变量
- int Index = a.length;// 数据索引变量
- System.out.print("排序前: ");
- for (i = 0; i < Index; i++)
- System.out.printf("%3s ", a[i]);
- System.out.println("");
- ShellSort(Index);
- System.out.print("排序后: ");
- for (i = 0; i < Index; i++)
- System.out.printf("%3s ", a[i]);
- System.out.println("");
- }
- public static void ShellSort(int Index) {
- int j, k; // 循环计数变量
- int Temp; // 暂存变量
- boolean Change; // 数据是否改变
- int DataLength; // 分割集合的间隔长度
- int Pointer; // 进行处理的位置
- DataLength = (int) Index / 2; // 初始集合间隔长度
- while (DataLength != 0) // 数列仍可进行分割
- { // 对各个集合进行处理
- for (j = DataLength; j < Index; j++) {
- Change = false;
- Temp = a[j]; // 暂存Data[j]的值,待交换值时用
- Pointer = j - DataLength; // 计算进行处理的位置
- // 进行集合内数值的比较与交换值
- while (Temp < a[Pointer] && Pointer >= 0 && Pointer <= Index) {
- a[Pointer + DataLength] = a[Pointer]; // 计算下一个欲进行处理的位置
- Pointer = Pointer - DataLength;
- Change = true;
- if (Pointer < 0 || Pointer > Index)
- break;
- }
- // 与最后的数值交换
- a[Pointer + DataLength] = Temp;
- if (Change) { // 打印排序结果
- System.out.print("排序中: ");
- for (k = 0; k < Index; k++)
- System.out.printf("%3s ", a[k]);
- System.out.println("");
- }
- }
- DataLength = DataLength / 2; // 计算下次分割的间隔长度
- }
5)快速排序
快速排序是目前已知的常用排序算法中最快的排序方法。
快速排序(Quicksort)是对冒泡排序的一种改进。
它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
优点:极快,数据移动少。
缺点:不稳定。
示例:
- public class Quicksort {
- static int count = 0;
- public static void main(String[] args) {
- int values[] = { 3, 9, 8, 23, 7, -2, 1, -9, 0, 16 };
-
- qsort(values, 0, (values.length - 1));
- System.out.printf("\n\n排序后的结果是:");
- for (int i = 0; i < values.length; i++) {
- System.out.printf("%d ", values[i]);
- }
- }
-
- public static void qsort(int values[], int left, int right) {
- int tmp = 0;
-
- System.out.printf("\n这个是第%d次排序的结果:", count);
- count++;
- for (int i = 0; i < values.length; i++) {
- System.out.printf("%d ", values[i]);
- }
-
- if (left < right) {
- tmp = partition(values, left, right);
- qsort(values, left, tmp);
- qsort(values, tmp + 1, right);
- }
- }
-
- public static int partition(int values[], int left, int right) {
- int i = 0, j = 0;
- int key = 0, tmp = 0;
- if (null == values) {
- return 0;
- }
- i = left;
- j = right;
- key = values[left];
- while (i < j) {
- while (values[j] > key) {
- --j;
- }
- tmp = values[i];
- values[i] = values[j];
- values[j] = tmp;
-
- while (values[i] < key) {
- i++;
- }
- tmp = values[i];
- values[i] = values[j];
- values[j] = tmp;
- }
- return i;
- }
- }
- public class Quicksort {
- static int count = 0;
- public static void main(String[] args) {
- int values[] = { 3, 9, 8, 23, 7, -2, 1, -9, 0, 16 };
- qsort(values, 0, (values.length - 1));
- System.out.printf("\n\n排序后的结果是:");
- for (int i = 0; i < values.length; i++) {
- System.out.printf("%d ", values[i]);
- }
- }
- public static void qsort(int values[], int left, int right) {
- int tmp = 0;
- System.out.printf("\n这个是第%d次排序的结果:", count);
- count++;
- for (int i = 0; i < values.length; i++) {
- System.out.printf("%d ", values[i]);
- }
- if (left < right) {
- tmp = partition(values, left, right);
- qsort(values, left, tmp);
- qsort(values, tmp + 1, right);
- }
- }
- public static int partition(int values[], int left, int right) {
- int i = 0, j = 0;
- int key = 0, tmp = 0;
- if (null == values) {
- return 0;
- }
- i = left;
- j = right;
- key = values[left];
- while (i < j) {
- while (values[j] > key) {
- --j;
- }
- tmp = values[i];
- values[i] = values[j];
- values[j] = tmp;
- while (values[i] < key) {
- i++;
- }
- tmp = values[i];
- values[i] = values[j];
- values[j] = tmp;
- }
- return i;
- }
- }
6)箱排序
箱排序(BinSort)的基本思想:箱排序也称桶排序(BucketSort),其基本思想是:设置若干个箱子,依次扫描待排序的记录R[0],R[1],…,R[n-1],把关键字等于k的记录全都装入到第k个箱子里(分配),然后按序号依次将各非空的箱子首尾连接起来(收集)。
优点:快。
缺点:数据范围必须为正整数并且比较小。
7)归并排序
归并排序是多次将两个或两个以上的有序表合并成一个新的有序表。最简单的归并是直接将两个有序的子表合并成一个有序的表。归并排序是稳定的排序.即相等的元素的顺序不会改变。
速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。
8)树形排序
树形排序的要素就是让所有的左子树都比根及右子树大,但不太稳定。
优点:效率高
2.数组的位置置换
我们可以发现在排序中都需要对满足条件的元素进行位置置换,所以我们可以把这部分相同的代码提取出来,单独封装成一个函数。
- private static void swap(int[] arr,int a,int b)
- {
- int temp=arr[a];
- arr[a]=arr[b];
- arr[b]=temp;
- }
二、数组的折半查找
二分查找又称折半查找
优点:比较次数少,查找速度快,平均性能好;
缺点:要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。
示例:
方式1
- public static int halfSearch(int[] arr,int key){
- int min,max,mid;
- min = 0;//小
- max = arr.length-1;//大
- mid = (max+min)/2;//中
- while(arr[mid]!=key ){
- if(key>arr[mid])
- min = mid + 1;
- else if(key<arr[mid])
- max = mid - 1;
- if(min>max)
- return -1;
- mid = (max+min)/2;
- }
- return mid;
- }
方式2
- public static int halfSearch_2(int[] arr,int key){
- int min = 0,max = arr.length-1,mid;
- while(min<=max){
- mid = (max+min)>>1;//>>1相当与/2
- if(key>arr[mid])
- min = mid + 1;
- else if(key<arr[mid])
- max = mid - 1;
- else
- return mid;
- }
- return -1;
- }
总结:
在真实开发用到的排序一般是java中已经定义好的一种排序方式。Arrays。
Arrays:此类包含用来操作数组(比如排序和搜索)的各种方法。此类还包含一个允许将数组作为列表来查看的静态工厂。对数组排序用的是sort方法。