常用算法java汇总
最近在面试的时候,面试官都会问到一些算法题,这里我把一些课本上有的(算法导论)算法的java实现版本整理一下,方便自己查阅,如果里面存在错误的话,请及时指正,谢谢。
1:快排
快排的思想是分支,具体介绍请查看别的博客,这里我主要说明两点内容:
1)为什么最后需要把你选择的某个anchor点交换,比如说,我在程序里面使用的输入数组的第一个元素,为什么需要把第一个元素和end指针(end指针用于从后往前找到小于anchor的点)进行交换?因为如果你不进行交换的话,对于一些偏序的情况,如倒序的情况,是不可行的。而且,每次交换元素之后保证了我们每次至少有一个元素是已经排好序的。
2)对于选择第一个元素作为anchor点时,必须首先从后开始往前找小于anchor的点,因为这样保证的end指针找的节点是小于anchor的,可以用于交换。如果反过来,首先从前找到大于anchor的点,那么end指向的点可能大于anchor,就不能用于交换(end到达start处停止循环)
package Algorithm;
public class QuickSort {
public static void main(String[] args) {
int arr[] = {10, 7, 8, 9, 1, 5};
//int arr[] = {10, 10, 10, 10, 10};
int n = arr.length;
QuickSort ob = new QuickSort();
ob.sort(arr, 0, n-1);
System.out.println("sorted array");
printArray(arr);
}
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low-1); // index of smaller element
for (int j=low; j<high; j++)
{
if (arr[j] <= pivot)
{
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// swap arr[i+1] and arr[high] (or pivot)
// 为什么要进行交换,因为保证第i+1位一定是已经排好序的,然后只需对前面和后面排序即可,不用对该位再进行排序
int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp;
return i+1;
}
public static int partion(int[] data, int startIndex, int endIndex) {
int start = startIndex;
int end = endIndex;
int pivot = data[startIndex];
while(start<end) {
//不能够从左先找,因为从左先找的话,找到的一定是一个大于pivot的数,因此无法和pivot互换
while(data[end]>pivot && start<end) {
end--;
}
while(data[start]<=pivot && start<end) {
start++;
}
int temp = data[start];
data[start] = data[end];
data[end] = temp;
}
int temp = data[end];
data[end] = data[startIndex];
data[startIndex] = temp;
return end;
}
void sort(int arr[], int low, int high)
{
if (low < high)
{
int pi = partion(arr, low, high);
// or int pi = partition(arr, low, high);
printArray(arr);
sort(arr, low, pi-1);
sort(arr, pi+1, high);
}
}
static void printArray(int arr[])
{
int n = arr.length;
for (int i=0; i<n; ++i)
System.out.print(arr[i]+" ");
System.out.println();
}
}
参考:
https://www.geeksforgeeks.org/quick-sort/
2:堆排序
堆排序的详细细节请查看别的博客,这里我主要说一点,就是建堆的时间复杂度是O(n),虽然建堆过程需要对非叶子节点进行堆维护过程,看起来像是O(NlogN),但是,因为不是所有节点都需要维护堆,而且需要维护的节点树高比较低,因此实际的时间复杂度上界是O(n),证明如下(拍自算法导论):
package Algorithm;
public class HeapSort {
public static void main(String[] args) {
int arr[] = {12, 11, 13, 5, 6, 7};
HeapSort ob = new HeapSort();
ob.sort(arr);
System.out.println("Sorted array is");
printArray(arr);
}
public void sort(int[] arr) {
int length = arr.length;
for(int i=length/2-1;i>=0;i--) {
heapify(arr, length, i);
}
for (int i=length-1; i>=0; i--)
{
// Move current root to end
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
void heapify(int arr[], int n, int i) {
int largest = i; // Initialize largest as root
int l = 2*i + 1; // left = 2*i + 1
int r = 2*i + 2; // right = 2*i + 2
// If left child is larger than root
if (l < n && arr[l] > arr[largest])
largest = l;
// If right child is larger than largest so far
if (r < n && arr[r] > arr[largest])
largest = r;
// If largest is not root
if (largest != i)
{
int swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
// Recursively heapify the affected sub-tree
heapify(arr, n, largest);
}
}
static void printArray(int arr[])
{
int n = arr.length;
for (int i=0; i<n; ++i)
System.out.print(arr[i]+" ");
System.out.println();
}
}
参考:
https://www.geeksforgeeks.org/heap-sort/