常见排序&查询算法Java代码实现

1. 排序算法代码实现

/**
 * ascending sort
 *  外层循环边界条件:总共需要冒泡的轮数--每一轮都将最大或最小的数冒泡到最后
 *  内层循环边界条件:冒泡数字移动的边界--最终数字需冒泡到此处
 *  时间复杂度:O(n^2)
 * @param arr
 */
public static void bubbleSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	for(int i = 0; i < arr.length - 1; i++) {
		for(int j = 0; j < arr.length - 1 - i; j++) {
			//冒泡:相邻两数比较,大的向后冒
			if(arr[j] > arr[j+1]) {
				int temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
}

/**
 * 每次都将未排序数组中的最大或最小元素找出来和第一个元素交换位置
 *  时间复杂度:O(n^2)
 * @param arr
 */
public static void selectSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	for(int i = 0; i < arr.length - 1; i++) {
		//寻找最小元素的下标,避免频繁交换数组
		int min = i;
		for(int j = i + 1; j < arr.length; j++) {
			if (arr[j] < arr[min]) {
				min = j;
			}
		}
		//将最小的元素交换到未排序数组的最前面
		int temp = arr[i];
		arr[i] = arr[min];
		arr[min] = temp;
	}
}

/**
 * 插入排序:顺次从数组中选择一个数,插入到前面已排序的数组中
 * 时间复杂度:O(n)~O(n^2)
 * @param arr
 */
public static void insertSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	for(int i = 1; i < arr.length; i++) {
		int value = arr[i];
		//插入的位置
		int j = 0;
		//循环i前面的数,若值比插入的值大,则顺次向后移动
		for (j = i - 1; j >= 0; j--) {
			if(arr[j] > value) {
				arr[j+1] = arr[j];
			} else {
				break;
			}
		}
		arr[j+1]=value;
	}
}

/**
 * 	希尔排序:插入排序的改进版,也称缩小增量排序
 *
 * @param arr
 */
public static void shellSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	int length = arr.length;
	//区间
	int gap = 1;
	while(gap < length) {
		gap = gap * 3 +1;
	}

	while(gap > 0) {
		for(int i = gap; i < length; i++) {
			int tmp = arr[i];
			int j = i -gap;
			//跨区间排序
			while(j >= 0 && arr[j] > tmp) {
				arr[j+gap] = arr[j];
				j -= gap;
			}
			arr[j + gap] = tmp;
		}
		gap = gap / 3;
	}
}

/**
 * 	归并排序--核心为分治法
 *	时间复杂度O(nlogn)
 * @param arr
 */
public static void mergeSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}
	int[] tmpArr = new int[arr.length];
	mSort(arr,tmpArr, 0, arr.length - 1);
}

private static void mSort(int[] arr, int[] tmpArr, int startIndex, int endIndex) {
	//边界条件:数组已不可再拆
	if (endIndex <= startIndex) {
		return;
	}

	//将数组对拆为前后两个数组
	int middleIndex = startIndex + (endIndex - startIndex)/2;
	mSort(arr, tmpArr, startIndex, middleIndex);
	mSort(arr, tmpArr, middleIndex + 1, endIndex);

	merge(arr, tmpArr, startIndex, middleIndex, endIndex);
}

private static void merge(int[] arr, int[] tmpArr, int startIndex, int middleIndex, int endIndex) {
	//将要合并的数组复制到临时数组
	for (int i = startIndex; i <= endIndex; i++) {
		tmpArr[i] = arr[i];
	}

	//左边数组起始下标
	int left = startIndex;
	//右边数组起始下标
	int right = middleIndex + 1;
	for(int k = startIndex; k <= endIndex; k++) {
		if (left > middleIndex) {
			arr[k] = tmpArr[right++];
		} else if (right > endIndex) {
			arr[k] = tmpArr[left++];
		} else if (tmpArr[left] < tmpArr[right]) {
			arr[k] = tmpArr[left++];
		} else {
			arr[k] = tmpArr[right++];
		}
	}
}

/**
 * 	快速排序:随机选取一个参考值,将比参考值小的数移到数组前段,大的值移到后段
 * 	以参考值为临界点递归拆分数组直至数组不能拆分,此时数组本身已排好序
 * 	快速排序时间复杂度为O(nlogn),对于逆序数组复杂度退化为O(n^2),为了避免极端情况,可随机选取参考值
 * @param arr
 */
public static void quickSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	qSort(arr , 0, arr.length - 1);
}

private static void qSort(int[] arr, int startIndex, int endIndex) {
	// 设置边界条件
	if (endIndex <= startIndex) {
		return;
	}

	// 将数组按参考值整理成比参考值小的前段和比参考值大的后段,返回参考值的位置
	int refIndex = partition(arr, startIndex, endIndex);

	// 参考值已确定排序后的位置,不参与数组拆分
	if (refIndex > startIndex) {
		qSort(arr, startIndex, refIndex - 1);
	}
	if (endIndex > refIndex) {
		qSort(arr, refIndex + 1, endIndex);
	}
}
private static int partition(int[] arr, int startIndex, int endIndex) {
	// 将数组中refValue的值与最后一个数交换,随机选取参考值可避免时间复杂度退化为O(n^2)
	int refIndex = startIndex + new Random().nextInt(endIndex - startIndex + 1);
	// 深坑,当两个数指向同一个时,会影响异或结果
	if (refIndex != endIndex) {
		arr[endIndex] = arr[endIndex] ^ arr[refIndex];
		arr[refIndex] = arr[endIndex] ^ arr[refIndex];
		arr[endIndex] = arr[endIndex] ^ arr[refIndex];
	}

	// 分组下标
	int partitionIndex = startIndex - 1;
	// 数组最后一个值为参考值,不参与循环
	for (int dataIndex = startIndex; dataIndex < endIndex; dataIndex++) {
		// 与参考值进行比较,若比参考值小,则移动到数组前面
		if ((arr[dataIndex] < arr[endIndex]) ) {
			// 始终指向最后一个确定比参考值小的值
			++partitionIndex;
			// 如果当前数据的位置与参考下标不一致,将此值与参考下标指向的值交换,保证小的值交换到前面
			if (partitionIndex != dataIndex) {
				arr[dataIndex] = arr[dataIndex] ^ arr[partitionIndex] ;
				arr[partitionIndex] = arr[dataIndex] ^ arr[partitionIndex];
				arr[dataIndex] = arr[dataIndex] ^ arr[partitionIndex];
			}
		}
	}
	// 将参考值交换到指定位置
	++partitionIndex;
	if (partitionIndex != endIndex) {
		arr[endIndex] = arr[endIndex] ^ arr[partitionIndex] ;
		arr[partitionIndex] = arr[endIndex] ^ arr[partitionIndex];
		arr[endIndex] = arr[endIndex] ^ arr[partitionIndex];
	}

	return partitionIndex;
}

/**
 *	堆排序--最大堆实现
 *	时间复杂度O(nlogn)
 * @param arr
 */
public static void heapSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	int length = arr.length;
	//构建堆
	buildHeap(arr, length);
	for (int i = length - 1; i > 0; i--) {
		//将堆元素与末位元素调换
		int temp = arr[0];
		arr[0] =arr[i];
		arr[i] = temp;
		//数组长度-1 隐藏堆尾元素
		length--;
		//将堆顶元素下沉,目的是将最大的元素浮到堆顶来
		sink(arr, 0, length);
	}
}
private static void buildHeap(int[] arr, int length) {
	for (int i = length / 2; i >= 0; i--) {
		sink(arr, i , length);
	}
}

private static void sink(int[] arr, int index, int length) {
	//左子节点下标
	int leftChild = 2 * index + 1;
	//右子节点下标
	int rigthChild = 2 * index + 2;
	//要调整的节点下标
	int present = index;

	//下沉左边
	if (leftChild < length && arr[leftChild] > arr[present]) {
		present = leftChild;
	}

	//下沉右边
	if (rigthChild < length && arr[rigthChild] > arr[present]) {
		present = rigthChild;
	}

	//如果下标不相等,证明调换过了
	if (present != index) {
		//交换值
		int temp = arr[index];
		arr[index] = arr[present];
		arr[present] = temp;

		//继续下沉
		sink(arr, present, length);
	}
}

/**
 *	计数排序--时间复杂度为O(n+m),空间大小取决于数组值,时间复杂度为O(n)
 *	问题点:数组中不能有负数,否则会抛出越界异常
 * @param arr
 */
public static void countSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	//找出数组中的最大值
	int max = arr[0];
	for(int i = 1; i < arr.length; i++) {
		if (arr[i] < 0) {
			throw new RuntimeException("Cannot use countsort! Array contains negative number.");
		}
		if (max < arr[i]) {
			max = arr[i];
		}
	}

	//利用最大值构建一个数组,用空间换时间
	int[] countArr = new int[max + 1];

	//计数
	for (int i = 0; i < arr.length; i++) {
		countArr[arr[i]]++;
	}

	int index = 0;
	for (int i = 0; i < countArr.length; i++) {
		while (countArr[i] > 0) {
			arr[index++] = i;
			countArr[i]--;
		}
	}
}

/**
 * 	桶排序--类似于Hash分桶策略
 * 	良好的分桶策略可实现O(n)时间复杂度
 * @param arr
 */
public static void bucketSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	//最大最小值
	int max = arr[0];
	int min = arr[0];
	int length = arr.length;

	for (int i = 1; i < length; i++) {
		if (arr[i] > max) {
			max = arr[i];
		} else if (arr[i] < min) {
			min = arr[i];
		}
	}

	//最大值与最小值的差
	int diff = max - min;

	//桶列表
	ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();
	for (int i = 0; i < length; i++) {
		bucketList.add(new ArrayList<>());
	}

	//每个桶的存数区间
	float section = (float)diff / (float)(length -1);

	//数据入桶
	for (int i = 0; i < length; i++) {
		//当前数除以区间得出存放桶的位置 减1后得出桶的下标
		int num = (int) (arr[i] / section) - 1;
		if (num < 0) {
			num = 0;
		}
		bucketList.get(num).add(arr[i]);
	}

	//桶内排序
	for (int i = 0; i < bucketList.size(); i++) {
		Collections.sort(bucketList.get(i));
	}

	//写入数据
	int index = 0;
	for (ArrayList<Integer> arrayList: bucketList) {
		for (int value : arrayList) {
			arr[index] = value;
			index++;
		}
	}
}

/**
 * 	基数排序
 * @param arr
 */
public static void radixSort(int[] arr) {
	if (arr == null) {
		throw new RuntimeException("Input arr is null!");
	}

	int length = arr.length;

	//最大值
	int max = arr[0];
	for(int i = 0;i < length;i++){
		if(arr[i] > max){
			max = arr[i];
		}
	}
	//当前排序位置
	int location = 1;

	//桶列表
	ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();

	//长度为10 装入余数0-9的数据
	for(int i = 0; i < 10; i++){
		bucketList.add(new ArrayList<>());
	}

	while(true)
	{
		//判断是否排完
		int dd = (int)Math.pow(10, (location - 1));
		if(max < dd){
			break;
		}

		//数据入桶
		for(int i = 0; i < length; i++)
		{
			//计算余数 放入相应的桶
			int number = ((arr[i] / dd) % 10);
			bucketList.get(number).add(arr[i]);
		}

		//写回数组
		int nn = 0;
		for (int i=0;i<10;i++){
			int size = bucketList.get(i).size();
			for(int ii = 0;ii < size;ii ++){
				arr[nn++] = bucketList.get(i).get(ii);
			}
			bucketList.get(i).clear();
		}
		location++;
	}
}

  2. 查询算法代码实现

/**
 *    顺序查找,即为遍历数组,时间复杂度为O(n)
 * @param arr
 * @param value
 * @return
 */
public static int sequentialSearch(int[] arr, int value) {
    if (arr == null) {
        throw new RuntimeException("Input arr is null!");
    }

    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == value) {
            return i;
        }
    }

    return -1;
}

/**
 *    二分查找针对以升序排列的数组进行,每次取数组的中间值进行查找
 *    时间复杂度为O(logn)
 * @param arr
 * @param value
 * @return
 */
public static int binarySearch(int[] arr, int value) {
    if (arr == null) {
        throw new RuntimeException("Input arr is null!");
    }

    int low = 0;
    int high = arr.length - 1;
    int mid = 0;
    while (low <= high) {
        mid = (low + high)/2;
        if (arr[mid] == value) {
            return mid;
        } else if (arr[mid] > value) {
            high = mid -1;
        } else {
            low = mid + 1;
        }
    }
    return -1;
}

/**
 *     二分查找--递归实现
 * @param arr    待查询数组
 * @param value    查找目标值
 * @param low    数组起始下标
 * @param high    数组结束下标
 * @return    目标值的下标
 */
public static int binarySearchByRecursion(int[] arr, int value, int low, int high) {
    if (arr == null) {
        throw new RuntimeException("Input arr is null!");
    }
    int mid = low + (high -low)/2;
    if (low == high && arr[mid] != value) {
        return -1;
    }
    if (arr[mid] == value) {
        return mid;
    } else if (arr[mid] > value) {
        return binarySearchByRecursion(arr, value, low, mid - 1);
    } else {
        return binarySearchByRecursion(arr, value, mid + 1, high);
    }
}

/**
 *     插值查找--递归实现,原理与二分查找类似,按目标值的大小计算在数组中的权重,适用于均有有序的数组
 * @param arr    待查询数组
 * @param value    查找目标值
 * @param low    数组起始下标
 * @param high    数组结束下标
 * @return    目标值的下标
 */
public static int insertionSearch(int[] arr, int value, int low, int high) {
    if (arr == null) {
        throw new RuntimeException("Input arr is null!");
    }
    // 按目标值与最小值的差估算插值下标的位置
    int mid = low + ((value - arr[low]) / (arr[high] - arr[low])) * (high -low);
    if (low == high && arr[mid] != value) {
        return -1;
    }
    if (arr[mid] == value) {
        return mid;
    } else if (arr[mid] > value) {
        return binarySearchByRecursion(arr, value, low, mid - 1);
    } else {
        return binarySearchByRecursion(arr, value, mid + 1, high);
    }
}

原文地址:https://www.cnblogs.com/beichenroot/p/11122212.html

时间: 2024-11-07 02:53:29

常见排序&查询算法Java代码实现的相关文章

算法-java代码实现希尔排序

希尔排序 第8节 希尔排序练习题 对于一个int数组,请编写一个希尔排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组.保证元素小于等于2000. 测试样例: [1,2,3,5,2,3],6 [1,2,2,3,3,5] Java (javac 1.7) 代码自动补全 1 import java.util.*; 2 3 public class ShellSort { 4 public int[] shellSort(int[] A, int n) { 5 int

算法-java代码实现计数排序

计数排序 第10节 计数排序练习题 对于一个int数组,请编写一个计数排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组. 测试样例: [1,2,3,5,2,3],6 [1,2,2,3,3,5] Java (javac 1.7) 代码自动补全 1 import java.util.*; 2 3 public class CountingSort { 4 public int[] countingSort(int[] A, int n) { 5 countingSo

十大排序算法 JAVA代码

冒泡排序 插入排序 选择排序 希尔排序 归并排序 快速排序 堆排序 计数排序 基数排序 桶排序  O是指计算机执行命令所需的时间 nlogn是算法的时间复杂度,一般排序用的是log2n 总体总结表:这个有个错误就是归并排序需要一个o(n)的辅助数组  冒泡排序 主要思想:外层循环从1到n-1,内循环从当前外层的元素的下一个位置开始,依次和外层的元素比较,出现逆序就交换. 特点:stable sort(稳定性排序).In-place sort(不占用额外的空间,只是交换元素) 最优复杂度:当输入数

排序与查找简单算法 java代码实现

最近整理了下以前的资料.有的算法没有实现,嘿嘿,以后再补吧! /** * 排序算法的分类如下:      * 1.插入排序(直接插入排序.折半插入排序.希尔排序):      * 2.交换排序(冒泡泡排序.快速排序):      * 3.选择排序(直接选择排序.堆排序):      * 4.归并排序:      *  关于排序方法的选择:      * (1)若n较小(如n≤50),可采用直接插入或直接选择排序.      *  当记录规模较小时,直接插入排序较好:否则因为直接选择移动的记录数少

算法-java代码实现基数排序

基数排序 第11节 基数排序练习题 对于一个int数组,请编写一个基数排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组.保证元素均小于等于2000. 测试样例: [1,2,3,5,2,3],6 [1,2,2,3,3,5] Java (javac 1.7) 代码自动补全 1 import java.util.*; 2 3 public class RadixSort { 4 // 各位装通法 5 public int[] radixSort(int[] A, in

算法-java代码实现堆排序

堆排序 第7节 堆排序练习题 对于一个int数组,请编写一个堆排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组. 测试样例: [1,2,3,5,2,3],6 [1,2,2,3,3,5] Java (javac 1.7) 代码自动补全 1 import java.util.*; 2 3 public class HeapSort { 4 public int[] heapSort(int[] A, int n) { 5 int lastIndex = n - 1;

C言语合并排序(兼并排序)算法及代码

合并排序也称兼并排序,其算法思惟是将待排序序列分为两局部,顺次对分得的两个局部再次运用合并排序,之后再对其停止兼并.仅从算法思惟上理解合并排序会认为很笼统,接下来就以对序列A[0], A[l]-, A[n-1]停止升序陈列来停止解说,在此采取自顶向下的完成办法,操作步调如下.(1)将所要停止的排序序列分为阁下两个局部,假如要停止排序的序列的肇端元素下标为first,最初一个元素的下标为last,那么阁下两局部之间的临界点下标mid=(first+last)/2,这两局部辨别是A[first -

C语言归并排序(合并排序)算法及代码

归并排序也称合并排序,其算法思想是将待排序序列分为两部分,依次对分得的两个部分再次使用归并排序,之后再对其进行合并.仅从算法思想上了解归并排序会觉得很抽象,接下来就以对序列A[0], A[l]-, A[n-1]进行升序排列来进行讲解,在此采用自顶向下的实现方法,操作步骤如下. (1)将所要进行的排序序列分为左右两个部分,如果要进行排序的序列的起始元素下标为first,最后一个元素的下标为last,那么左右两部分之间的临界点下标mid=(first+last)/2,这两部分分别是A[first -

Shell排序(希尔)算法--java

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组内进行直接插入排序:然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<:…<d2<d1),即所有记录放在同一组中进行直接插入排序为止. 该方法实质上是一种分组插入方法. 原理图: 源代码 1 package com.zc.manythread; 2 /** 3 * 4 * @author 偶my耶 5 * 6 */ 7