时间复杂度为
关于时间复杂度
平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。
线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;
O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序
线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。
关于稳定性
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。
名词解释:
n:数据规模
k:"桶"的个数
In-place:占用常数内存,不占用额外内存
Out-place:占用额外内存
稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同
1.冒泡排序
从前往后选择最小的放到最后
public static int[] maopao(int[] nums){
int temp=0;
for(int i=0;i<nums.length-1;i++){
for(int j=0;j<nums.length-1-i;j++){
if(nums[j]>nums[j+1]){
temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
return nums;
}
2.选择排序
当前设置为最小值,找到后面最小的与之互换
public static int[] xuanze(int[] nums){
for (int i=0;i<nums.length-1;i++){
int min=nums[i];
int minindex=i;
for (int j=i+1;j<nums.length;j++){
if(min>nums[j]){
min=nums[j];
minindex=j;
}
}
nums[minindex]=nums[i];
nums[i]=min;
}
return nums;
}
3.插入排序
从1到最后,找到小的就一步一步往前插入
public static int[] charu(int[] nums){
for(int i=1;i<nums.length;i++){
int insertindex=i-1;
int insert=nums[i];
while(insertindex>=0&&insert<nums[insertindex]){
nums[insertindex+1]=nums[insertindex];
insertindex--;
}
nums[insertindex+1]=insert;
}
return nums;
}
4.希尔排序(插入排序高效版本)
a.交换式
public static int[] xier(int[] nums){
int len=nums.length;
int temp;
for(int gap=len/2;gap>0;gap/=2){
for(int i=gap;i<len;i++){
for(int j=i-gap;j>=0;j-=gap){
if(nums[j]>nums[j+gap]){
temp=nums[j];
nums[j]=nums[j+gap];
nums[j+gap]=temp;
}
}
}
}
return nums;
}
b.移动式
public static int[] xier2(int [] nums){
int len=nums.length;
for(int gap=len/2;gap>0;gap/=2){
for(int i=gap;i<len;i++){
int j=i;
int temp=nums[j];
if(nums[j]<nums[j-gap]){
while(j-gap>=0&&temp<nums[j-gap]){
nums[i]=nums[i-gap];
j-=gap;
}
nums[j]=temp;
}
}
}
return nums;
}
5.快速排序
public static void kuai(int[] nums,int left,int right){
if(left>right){
return;
}
int l=left;
int r=right;
int piviot=nums[l];
int temp=0;
while(l!=r){
while(l<r&&nums[r]>=piviot){
r--;
}
while(l<r&&nums[l]<=piviot){
l++;
}
temp=nums[l];
nums[l]=nums[r];
nums[r]=temp;
}
nums[left]=nums[l];
nums[l]=piviot;
kuai(nums,left,l-1);
kuai(nums,r+1,right);
}
6.归并排序
public static void mergeSort(int[] arr,int left,int right,int[] temp){
if (left<right){
int mid=(left+right)/2;
mergeSort(arr,left,mid,temp);
mergeSort(arr,mid+1,right,temp);
guib(arr,left,mid,right,temp);
}
}
public static void guib(int[] arr,int left,int mid,int right,int[] temp){
int i=left;
int j=mid+1;
int t=0;
while (i<=mid&&j<=right){
if(arr[i]<=arr[j]){
temp[t]=arr[i];
t++;
i++;
}else{
temp[t]=arr[j];
t++;
j++;
}
}
while(i<=mid){
temp[t]=arr[i];
t++;
i++;
}
while(j<=right){
temp[t]=arr[j];
t++;
j++;
}
t=0;
int templest=left;
while (templest<=right){
arr[templest]=temp[t];
t++;
templest++;
}
}
7.基数排序
public static void radisSort(int[] arr){
int max=arr[0];
for(int i=1;i<arr.length;i++){
if(arr[i]>max){
max=arr[i];
}
}
int maxLength=(max+"").length();
int[][] bucket=new int[10][arr.length];
int[] bucketcount=new int[10];
for (int i=0,n=1;i<maxLength;i++,n*=10){
for(int j=0;j<arr.length;j++){
int digitOfElement=arr[j]/n%10;
bucket[digitOfElement][bucketcount[digitOfElement]]=arr[j];
bucketcount[digitOfElement]++;
}
int index=0;
for (int k=0;k<bucketcount.length;k++){
if (bucketcount[k]!=0){
for (int l=0;l<bucketcount[k];l++){
arr[index]=bucket[k][l];
index++;
}
}
bucketcount[k]=0;
}
}
}
8.堆排序
public static void heap(int[] arr){
for(int i=arr.length/2-1;i>=0;i--){
dui(arr,i,arr.length);
}
for(int i=arr.length-1;i>0;i--){
int temp=arr[0];
arr[0]=arr[i];
arr[i]=temp;
dui(arr,0,i);
}
}
public static void dui(int[] arr,int i,int length){
int temp=arr[i];
for(int k=i*2+1;k<length;k=k*2+1){
if(k+1<length&&arr[k+1]>arr[k]){
k++;
}
if(arr[k]>temp){
arr[i]=arr[k];
i=k;
}
else{
break;
}
}
arr[i]=temp;
}
9.桶排序
public static double[] bucketSort(double[] array){
//得到数列的最大值和最小值,并计算出差值d
double max=array[0];
double min=array[0];
for (int i=1;i<array.length;i++){
if (array[i]>max){
max=array[i];
}
if (array[i]<min){
min=array[i];
}
}
double d=max-min;
//初始化桶
int bucketNum=array.length;
ArrayList<LinkedList<Double>> bucketList=new ArrayList<LinkedList<Double>>(bucketNum);
for (int i=0;i<bucketNum;i++){
bucketList.add(new LinkedList<Double>());
}
//遍历原始数组将每个元素放入桶中
for (int i=0;i<array.length;i++){
int num=(int)((array[i]-min)*(bucketNum-1)/d);
bucketList.get(num).add(array[i]);
}
//对每个桶内部进行排序
for(int i=0;i<bucketList.size();i++){
// 使用Collections.sort,其底层实现基于归并排序或归并排序的优化版本
Collections.sort(bucketList.get(i));
}
//输出全部元素
double[] sortedArray=new double[array.length];
int index=0;
for (LinkedList<Double> list:bucketList) {
for (double element:list){
sortedArray[index]=element;
index++;
}
}
return sortedArray;
}
10.计数排序
package pers.chh3213.sort;
import java.util.Arrays;
/**
*
* CountingSort.java
* @Description 计数排序
* @author chh3213
* @version
* @date 2022年2月15日上午10:46:13
*/
public class CountingSort{
public static void main(String[] args) {
CountingSort cSort = new CountingSort();
int[] arr = {9, 16, 31, 23, 30, 49, 25, 21, 30};
int[] result = cSort.countingSort(arr);
System.out.println(Arrays.toString(result));
}
public int[] countingSort(int[] arr) {
int maxValue = getMaxValue(arr);
// 创建一个新数组,长度为max+1
int countLen = maxValue+1;
int[] count = new int[countLen];
//统计数组中每个值为i的元素出现的次数,存入数组的第i项
for (int i : arr) {
count[i]++;
}
int[] result = new int[countLen];
// 创建结果数组的起始索引
int sortedIndex = 0;
// 遍历计数数组,将计数数组的索引填充到结果数组中
for (int i = 0; i < countLen; i++) {
while(count[i]>0) {
result[sortedIndex++]=i;
count[i]--;
}
}
return result;
}
/**
* 找出待排序的数组中最大的元素
* @param arr 待排序的数组
* @return 返回最大值
*/
public int getMaxValue(int[] arr) {
int maxValue = arr[0];
for (int i = 0; i < arr.length; i++) {
if(maxValue<arr[i]) {
maxValue=arr[i];
}
}
return maxValue;
}
}
查找算法
1.线性查找算法
public class seqSearch {
public static void main(String[] args) {
int[] arr = {1,9,11,-1,34,89,17,3,5,36,98,89};
System.out.println(seqSearch(arr,89));
}
public static HashSet<Integer> seqSearch(int[] arr, int value ){
//线性查找为逐一比对,返现有相同的值时,返回下标
HashSet<Integer> hashMap = new HashSet<>();
for (int j = 0;j < arr.length;j++){
if (arr[j] == value){
hashMap.add(j);
}
}
return hashMap;
}
}
2.二分查找
(1)左闭右闭
class Solution {
public int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
}
a.查找左边界
public static void main(String[] args) {
int[] num = {1,3,5,6,7,7,7,7,7,9};
int left=0;
int right=num.length-1;
int target=7;
while(left<=right){
int mid=(left+right)/2;
if (target>num[mid]){
left=mid+1;
} else {
right=mid-1;
}
}
System.out.println(left);
//System.out.println(right);
}
b.查找右边界
public static void main(String[] args) {
int[] num = {1,3,5,6,7,7,7,7,7,9};
int left=0;
int right=num.length-1;
int target=7;
while(left<=right){
int mid=(left+right)/2;
if (target>=num[mid]){
left=mid+1;
} else {
right=mid-1;
}
}
System.out.println(right);
}
(2)左闭右开
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length;
while (left < right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;
}
return -1;
}
}
3.差值查找
public static int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) *(target - nums[left]) / (nums[right] - nums[left]);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
4.斐波那契查找
public static int fibSearch(int[] arr,int key){
int low = 0;
int high = arr.length - 1;
int k = 0; //表示斐波那契分割数值的下标
int mid = 0; //存放mid值
int f [] = fib();
//获取到斐波那契分割数值的下标
while (high > f[k] - 1){
k++;
}
//f[k]的值可能大于arr的长度
int[] temp = Arrays.copyOf(arr,f[k]);
for (int i = high + 1;i < temp.length;i++){
temp[i] = arr[high];
}
//使用while循环来处理,找到数 key
while (low <= high){ //只要这个条件满足,就可以一直找
mid = low + f[k - 1] - 1;
if (key < temp[mid]){
high = mid - 1;
k--;
}else if (key > temp[mid]){
low = mid + 1;
k -= 2;
}else {
if (mid <= high){
return mid;
}else {
return high;
}
}
}
return -1;
}
//构造斐波那契数列
public static int[] fib(){
int[] fib = new int[maxSize];
fib[0] = 1;
fib[1] = 1;
for (int i = 2;i < maxSize;i++){
fib[i] = fib[i-1] + fib[i-2];
}
return fib;
}
KMP
public static int[] kmpnext(String dest){
/* 初始化;
处理前后缀不同情况;
处理前后缀相同情况;
给next[]数组赋值。*/
int [] next=new int[dest.length()];
next[0]=0;
for (int i=1,j=0;i<dest.length();i++){
while(j>0&&dest.charAt(i)!=dest.charAt(j)){
j=next[j-1];
}
if (dest.charAt(i)==dest.charAt(j)){
j++;
}
next[i]=j;
}
return next;
}
public static int kmpsearch(String str1,String str2,int[] next){
for (int i=0,j=0;i<str1.length();i++){
while (j>0&&str1.charAt(i)!=str2.charAt(j)){
j=next[j-1];
}
if (str1.charAt(i)==str2.charAt(j)){
j++;
}
if (str2.length()==j){
return i-j+1;
}
}
return -1;
}