排序大的分类可以分为两种,内排序和外排序,在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,那么称之为外排序
内排序分为一下几类
- 插入排序: 直接插入排序,二分法插入排序,希尔排序
- 选择排序:简单选择排序,堆排序。
- 交换排序: 冒泡排序,快速排序
- 归并排序
- 基数排序
1.插入排序
思想: 每步将一个待排序的记录,按照其顺序码大小插入到前面已经排序的字节序列的合适位置,直到全部插入排序完为止
public class directSort{
int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
for(int i = 1; i < a.length; i++){
//待插入元素
int temp = a[i];
int j;
for(j = i-1; j>=0;j--){
if (a[j] > temp){
a[j+1] = a[j];
} else {
break;
}
}
a[j+1] = temp;
}
System.out.println();
System.out.println("排序之后:");
System.out.println(Arrays.toString(a));
}
直接插入排序是稳定的排序,最坏的情况下,时间复杂度为o(n*n) 平均时间复杂度是o(n2)
2.二分法插入排序
思想:与直接插入一样,只是找合适的插入位置的方式不同,这里是按照二分法找到合适的位置,可以减少比较的次数
代码:
public class DivideSort{
public static void main(String[] args) {
int[] a={49,38,65,97,176,213,227,49,78,34,12,164,11,18,1};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
//二分插入排序
sort(a);
System.out.println();
System.out.println("排序之后:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
private static void sort(int[] a){
for(int i = 0;i < a.length;i++){
int temp = a[i];
it left = 0;
int right = i-1;
int mid = 0;
while(left <= right){
mid = (left+right)/2;
if(temp<a[mid]){
right = mid-1;
}else{
left = mid+1;
}
}
for(int j = i-1;j >= left; j--){
a[j+1] = a[j];
}
if(left != i){
a[left] = temp;
}
}
}
}
二分法插入排序也是稳定的,二分法插入排序的比较次数与待排序记录的初始化状态无关,仅仅依赖于记录的个数,当n较大的时候效率较高,平均比较次数为O(n2)
3.希尔排序
public class shellSort(){
public static void main(String[] args){
int[] a = {49,38,65,97,76,13,27,49,78,34,12,64,1};
System.out.println("排序之前: ");
for(int i = 0;i < a.length;i++){
System.out.print(a[i]+" ");
}
//希尔排序
int d = a.length;
while(true){
d = d/2;
for(int x = 0;x<d;x++){
for(int i = x+d;i<a.length;i=i+d){
int temp = a[i];
int j;
for(j = i-d;j>=0;j--){
a[j+d]=a[j];
}
a[j+d] = temp;
}
}
if(d == 1){
break;
}
}
System.out.println(Arrays.toString(a));
}
}
希尔排序的平均时间复杂度为O(nlogn).
4.选择排序
思想:每趟从待排序的记录序列中选择关键字最小的记录放置到已排序表的最前位置,直到全部排完。
public class SimpleSelectSort{
public static void main(String[] args) {
int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1,8};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
for(int i = 0;i < a.length; i++){
int min = a[i]; //存储最小数
n = i; //存储最小索引
for(int j = i+1;j<a.length;j++){
if(a[j]<min){
min = a[j];
n = j;
}
}
a[n] = a[i];
a[i] = min;
}
System.out.println(Arrays.toString(a));
}
}
5.堆排序
public vlass HeapSort{
public static void main(String[] args){
int[] a={49,38,65,97,76,13,27,49,78,34,12,64};
int arrayLength=a.length;
//循环建堆
for(int i=0;i<arrayLength-1;i++){
//建堆
buildMaxHeap(a,arrayLength-1-i);
//交换堆顶和最后一个元素
swap(a,0,arrayLength-1-i);
System.out.println(Arrays.toString(a));
}
}
public static void buildMaxHeap(int[] data,int lastIndex){
//从lastIndex处节点(最后一个节点)的父节点开始
for(int i = (lastIndex-1)/2;i>=0;i--){
//k保存正在判断的节点
int k = i;
//如果k节点的子节点存在
while(k*2+1<=lastIndex){
//将k点左子节点的索引赋值给biggerIndex
int biggerIndex = 2*k+1;
//如果biggerIndex小于lastIndex,代表k节点的右子节点存在
if(biggerIndex < lastIndex){
//如果右子节点的值较大
if(data[biggerIndex]<data[biggerIndex+1]){
//biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
}
//如果k节点的值小于其较大子节点的值
if(data[k] < data[biggerIndex]){
//交换他们
swap(data,k,biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k = biggerIndex;
} else {
break;
}
}
}
}
private static void swap(int[] data,int i,int j){
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
}
堆排序也是一种不稳定的排序算法,最坏的时间复杂度是O(nlogn)
6.冒泡排序
public class BubbleSort{
public static void main(String[] args){
int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1,8};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
//冒泡排序
for(int i = 0;i < a.length; i++){
for(int j = 0;i < a.length-i-1;j++){
//这里-i主要是每遍历一次都把最大的i个数沉到最底下去了,没有必要再进行排序
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(a))
}
}
冒泡排序是一种稳定的排序方法
7.快速排序
public class QuickSort{
public static void main(String[] args){
int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1,8};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
//快速排序
quick(a);
System.out.println(Arrays.toString(a));
}
private static void quick(int[] a){
if(a.length > 0){
quickSort(a,0,a.length-1);
}
}
private static void quickSort(int[] a,int low,int high){
if(low < high){
int middle = getMiddle(a,low,high);
quickSort(a,0,middle-1);
quickSort(a,middle+1,high);
}
}
private static int getMiddle(int[] a,int low,int high){
int temp = a[low];
while(low < high){
//找到比基准元素更小的元素位置
while(low < high && a[high] >= temp){
high--;
}
a[low] = a[high];
while(low < high && a[low]<= temp){
low++;
}
a[high] = a[low];
}
a[low] = temp;
return low;
}
}
快速排序是不稳定的排序
n越大使用快速排序越好