1 插入的时间复杂度
附:选择排序:思想为从所有序列中找最小的放第一个位置,之后从剩余的元素中找最小的放第二个位置,直到所有的。时间复杂度为O(n*n)。
折半插入排序(二分插入排序):在直接插入排序的基础上,对插入A[i]进行了修改,直接插入排序是从后向前比较,而折半插入排序为直接从A[i-1/2]那个位置进行比较,大了在[i-1/2]-A[i-1]查找,否则在A[0]-A[i-1/2]找,比直接插入减少了比较次数,单是元素移动次数不变,所以,时间复杂度仍为O(n^2)。
2 查找的时间复杂度
2.1 二分查找
二分查找又称折半查找,优点是查找速度快,平均性能好,缺点是待查表为有序表,且插入、删除困难。
适用于:不经常变动而查找频繁的有序列表。
根据比较中间关键字来查找需要查找的关键字。
二分查找法的时间复杂度是O(log(n)),最坏情况下为O(n)
3代码实现
3.1 冒泡排序
package sort;
/*
比较相邻的元素,如果第一个比第二个大,则交换他们两个,依次类推
平均O(n*2) 最坏O(n*2),最好O(n) 空间O(1) 稳定,简单
输出为:
排序前为:1 4 6 2 3 7 9 5 10 0
排序后为:0 1 2 3 4 5 6 7 9 10
* */
public class BubbleSort {
public static void bubbleSort(int[] numbers){
int length=numbers.length;
int j,temp;
System.out.print("排序前为:");
for(j=0;j<length;j++){
System.out.print(numbers[j]+" ");
}
System.out.println();
for(int i=0;i<length-1;i++){
for(j=0;j<length-1-i;j++){
if(numbers[j]>numbers[j+1]){
temp=numbers[j];
numbers[j]=numbers[j+1];
numbers[j+1]=temp;
}
}
}
System.out.print("排序后为:");
for(j=0;j<length;j++){
System.out.print(numbers[j]+" ");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] numbers={1,4,6,2,3,7,9,5,10,0};
bubbleSort(numbers);
}
}
3.2 快速排序
下面为数组输出函数
public static void printArray(int[] num){
for(int i=0;i<num.length;i++){
System.out.print(num[i]+" ");
}
}
/*
快速排序(平均为:O(nlogn),最坏为O(n*n) ,最好为O(nlogn),空间为O(nlogn),不稳定,较复杂)
从数列中挑出一个元素,称为基准,重新排列数列,所有比基准小的放到基准之前,所有比基准大的放到基准后面,之后递归的进行排列
输出为:
基准为:4排序后为:-4 0 2 1 3 4 9 5 10 7 11 6
基准为:-4排序后为:-4 0 2 1
基准为:0排序后为:0 2 1
基准为:2排序后为:1 2
基准为:9排序后为:6 5 7 9 11 10
基准为:6排序后为:5 6
基准为:11排序后为:10 11
结果为:
快速排序原先数组为:
4 6 2 1 3 7 9 5 10 0 11 -4 12
快速排序结果为:
-4 0 1 2 3 4 5 6 7 9 10 11 12
*
*/
//快速排序,取一个基准,把大于基准的排到右侧,小于基准的排到左侧。
public class QuickSort {
public static int[] qsort(int arr[], int start, int end) {
int base = arr[start];
int i = start;
int j = end; while (i < j) {
// 大于基准,符合右面
while ((i < j) && (arr[j] > base)) {
j--;
} // 小于基准,符合左面
while ((i < j) && (arr[i] < base)) {
i++;
}
// 此时出现右侧的比基准小,而左侧比基准大,如果相等,则忽略,否则交换,重新排序
if ((arr[i] == arr[j]) && (i < j)) { // 相等
i++; } else {// 不相等,则交换
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp; }
}
// 一次排序后,基准在中间,此时,左侧都小于基准,继续排序
if (i - 1 > start) {
arr = qsort(arr, start, i - 1);
}
// 一次排序后,基准在中间,此时,右侧都大于基准,继续排序
if (j + 1 < end) {
arr = qsort(arr, j + 1, end);
}
return arr;
} public static void main(String[] args) {
int arr[] = new int[] { 32, 43, 12, 5, 18, 2 };
arr = qsort(arr, 0, arr.length - 1);
System.out.print("排序后结果如下:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
} }
}
3.3 选择排序
/*
选择排序-平均-最坏-最好,均为O(n*n),
在未排序中找到最小的放在起始位置,再从剩余未排序的找出最小元素,依次类推
输出为:
选择排序原先数组为:
4 6 2 1 3 7 9 5 10 0 11 -4 12
选择排序结果为:
-4 0 1 2 3 4 5 6 7 9 10 11 12
*/
public static void selectSort(int[] num){
int length=num.length;
int i,j,min = 0;
for(i=0;i<length-1;i++){
min=i;
for(j=i+1;j<length;j++){
if(num[min]>num[j]){
min=j;
}
}
if(min==i){ //第一个为最小的元素,无需交换
//System.out.println();
//System.out.println(" 第"+(i+1)+"无需移动,值为: "+num[i]);
}else{ //需要交换
//System.out.println();
//System.out.println(" 第"+(i+1)+"与第"+(min+1)+"个交换,值分别为 "+num[i]+"和"+num[min]);
int temp=num[i];
num[i]=num[min];
num[min]=temp;
}
}
}
主方法调用为:
/*选择排序 start*/
int[] numbers2={4,6,2,1,3,7,9,5,10,0,11,-4,12};
System.out.println("\n\n选择排序原先数组为:");
printArray(numbers2);
selectSort(numbers2);
System.out.println("\n选择排序结果为:");
printArray(numbers2);
/*选择排序 end*/
3.4 插入排序
/*
插入排序:平均为O(n*n),最坏O(n*n),最好O(n),空间为O(1),稳定,简单
1.从第一个元素开始,该元素已经被认为排好序了
2.取下一个元素,在已经排好序的元素中,从后向前排
3.如果该元素大于新元素,将该元素移到下一个位置
4.重复步骤3,直到找到已排好序的元素小于或者等于新元素的位置
5.将新元素插入到该位置
6.重复步骤2
输出为:
插入排序原先数组为:
4 6 2 1 3 7 9 5 10 0 11 -4 12
插入排序结果为:
-4 0 1 2 3 4 5 6 7 9 10 11 12
*/
public static void insertSort(int[] num){
int length=num.length;
int temp,j;
for(int i=1;i<length;i++){
temp=num[i];//新的元素
for(j=i;j>0&&temp<num[j-1];j--){
num[j]=num[j-1];
}
num[j]=temp;
}
}
主方法调用:
/*插入排序 start*/
int[] numbers3={4,6,2,1,3,7,9,5,10,0,11,-4,12};
System.out.println("\n\n插入排序原先数组为:");
printArray(numbers3);
insertSort(numbers3);
System.out.println("\n插入排序结果为:");
printArray(numbers3);
/*插入排序 end*/
3.5 希尔排序
package algorithm;
//希尔排序
/*
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 =1( < …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
//如0 1 2 3 4 5 6 7 8 9 一共10个元素
增量:5 2 1
5的话,0-5 1-6- 2-7 3-8 4-9 开始0-4
2增量:0-2-4-6-8 1-3-5-7-9 开始0-1
1增量:0-1-2-3-4-5-6-7-8-9 开始0
*/
public class ShellSort {
public static void sort(int[] ints){
if(ints==null){
return;
}
int length=ints.length;
int increate=length/2;
for(;increate>=1;increate=increate/2){
System.out.println("i="+increate);
for(int j=increate;j<length;j=j+increate){
int tmp=ints[j];
int h=j-increate;
while(h>=0&&ints[h]>tmp){
ints[h+increate]=ints[h];
h=h-increate;
}
ints[h+increate]=tmp;
System.out.println(ints);
}
System.out.println(ints);
}
for(int i=0;i<ints.length;i++){
System.out.print(" "+ints[i]);
}
}
public static void main(String[] args) {
int[] tmp={0,3,5,6,1,2,4,7,8,9}; sort(tmp);
}}
3.6 归并排序
/*
归并排序:平均为O(nlogn),最坏O(nlogn),最好O(nlogn),空间O(n),稳定,较复杂
将一个数组分为2个,2个分为4个,一直到只有1个元素,后再开始合并元素,4合为2,2合为1,即可。
实例:
归并排序原先数组为:
16 4 6 2 1 3 7 9 5 10 0 11 -4 15
归并排序结果为:
-4 0 1 2 3 4 5 6 7 9 10 11 15 16
*/
package algorithm;
/*
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
*/
public class GuibingSort {
public static int[] mergeSort(int[] nums, int l, int h) {
if (l == h)
return new int[] { nums[l] };
int mid = l + (h - l) / 2;
int[] leftArr = mergeSort(nums, l, mid); //左有序数组
int[] rightArr = mergeSort(nums, mid + 1, h); //右有序数组
int[] newNum = new int[leftArr.length + rightArr.length]; //新有序数组
int m = 0, i = 0, j = 0;
while (i < leftArr.length && j < rightArr.length) {
newNum[m++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++];
}
while (i < leftArr.length)
newNum[m++] = leftArr[i++];
while (j < rightArr.length)
newNum[m++] = rightArr[j++];
return newNum;
}
public static void main(String[] args) {
int[] nums = new int[] { 9, 8, 7, 6, 5, 4, 3, 2, 10 ,1};
int[] newNums = mergeSort(nums, 0, nums.length - 1);
for (int x : newNums) {
System.out.print(x+" ");
}
}
}
3.7 堆排序
/*
堆排序:最好最坏平均均为O(nlogn),空间为O(1),不稳定,较复杂
整个过程为建堆和交换的过程,从第一个非叶子节点开始,比较节点和它的左右子节点,保证最大的为根节点
实例:
堆排序原先数组为:
16 4 6 2 1 3 7 9 5 10 0 11 -4 15
堆排序结果为:
-4 0 1 2 3 4 5 6 7 9 10 11 15 16
*/
package algorithm;
/*
//https://baike.baidu.com/item/%E5%A0%86%E6%8E%92%E5%BA%8F/2840151?fr=aladdin
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
//需要构建最大堆或者最小堆
最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。
最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。
* */
public class HeapSort {
/**
* 选择排序-堆排序
* @param array 待排序数组
* @return 已排序数组
*/
public static int[] heapSort(int[] array) {
//这里元素的索引是从0开始的,所以最后一个非叶子结点array.length/2 - 1
for (int i = array.length / 2 - 1; i >= 0; i--) {
adjustHeap(array, i, array.length); //调整堆
}
// 上述逻辑,建堆结束
// 下面,开始排序逻辑
for (int j = array.length - 1; j > 0; j--) {
// 元素交换,作用是去掉大顶堆
// 把大顶堆的根元素,放到数组的最后;换句话说,就是每一次的堆调整之后,都会有一个元素到达自己的最终位置
swap(array, 0, j);
// 元素交换之后,毫无疑问,最后一个元素无需再考虑排序问题了。
// 接下来我们需要排序的,就是已经去掉了部分元素的堆了,这也是为什么此方法放在循环里的原因
// 而这里,实质上是自上而下,自左向右进行调整的
adjustHeap(array, 0, j);
}
return array;
}
/**
* 整个堆排序最关键的地方
* @param array 待组堆
* @param i 起始结点
* @param length 堆的长度
*/
public static void adjustHeap(int[] array, int i, int length) {
// 先把当前元素取出来,因为当前元素可能要一直移动
int temp = array[i];
for (int k = 2 * i + 1; k < length; k = 2 * k + 1) { //2*i+1为左子树i的左子树(因为i是从0开始的),2*k+1为k的左子树
// 让k先指向子节点中最大的节点
if (k + 1 < length && array[k] < array[k + 1]) { //如果有右子树,并且右子树大于左子树
k++;
}
//如果发现结点(左右子结点)大于根结点,则进行值的交换
if (array[k] > temp) {
swap(array, i, k);
// 如果子节点更换了,那么,以子节点为根的子树会受到影响,所以,循环对子节点所在的树继续进行判断
i = k;
} else { //不用交换,直接终止循环
break;
}
}
}
/**
* 交换元素
* @param arr
* @param a 元素的下标
* @param b 元素的下标
*/
public static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
public static void main(String[] args){
int[] ints={1,2,6,0,3,4,5,9,7,8,10};
int[] result=heapSort(ints);
for(int i=0;i<result.length;i++){
System.out.print(" "+result[i]);
}
}
}