常用算法java汇总

常用算法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; jpivot && start

参考:

https://www.geeksforgeeks.org/quick-sort/

改进快排

快排对于一些极端的数据来说,可能会具有较低的性能,比如说顺序,倒序,很多数相等,等等。可以通过一些手段来提升这些情况的快排性能。

1)对于顺序,逆序来说,可以先对数据进行shuffle,打乱顺序之后在进行快排,下面仅仅写出shuffle函数:

//O(n)
private static void shuffleArray(int[] ar) {
   Random rnd = new Random();
   for (int i = ar.length - 1; i > 0; i--) {
       int index = rnd.nextInt(i + 1); // random between 0 and i
       exchange(ar, i, index);
   }
}

public static void exchange(int[] input, int i, int j) {
	int temp = input[i];
	input[i] = input[j];
	input[j] = temp;
}

2)对于很多数据相等,比如说全是0,快排的时间复杂度非常高,相当于每次产生一个长度为n-1和1的子序列,因此时间复杂度是O(N^{2} ),因此,我们可以把每次和pivot相等的数据找出来,处理剩下的不相等的子序列,那么效率就很高了。该方法叫three-way-quicksort,详情请查看https://dzone.com/articles/algorithm-week-quicksort-three,下面是代码:

package Algorithm;

import java.util.Random;

public class ThreeWayQuickSort {

	public static void main(String[] args) {
		
		int dataSize = 1000000;
		int oneRate = 100;
		int[] arr = generateData(dataSize, oneRate);
        int n = arr.length; 
  
        ThreeWayQuickSort ob = new ThreeWayQuickSort(); 
        ob.sort(arr, 0, n-1); 
  
        System.out.println("sorted array:"); 
        printArray(arr); 
	}

	public void sort(int[] input, int lowIndex, int highIndex) {
	      
	      
	      if (highIndex<=lowIndex) return;
	      //lt - gt is same num as pivot
	      //lt is the left most index of pivot
	      int lt=lowIndex;
	      int gt=highIndex;
	      int i=lowIndex+1;
	      
	      int pivotIndex=lowIndex;
	      int pivotValue=input[pivotIndex];
	      
	      
	      while (i<=gt){
	          
	          
	          if (input[i]

2:堆排序

堆排序的详细细节请查看别的博客,这里我主要说一点,就是建堆的时间复杂度是O(n),虽然建堆过程需要对非叶子节点进行堆维护过程,看起来像是O(NlogN),但是,因为不是所有节点都需要维护堆,而且需要维护的节点树高比较低,因此实际的时间复杂度上界是O(n),证明如下(拍自算法导论):

常用算法java汇总_第1张图片

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

参考:

https://www.geeksforgeeks.org/heap-sort/

3:产生排列组合

使用迭代的方法,产生数据的组合以及排列。下面的代码中,permute代表产生排列,combination代表组合,排列的代码参考自"剑指offer",组合的代码是自己写的,如果有问题请指正。

package Algorithm;

import java.util.ArrayList;
import java.util.Collection;

public class Permutation {

	public static void main(String[] args) {
		int[] arr = new int[] {1,2,3};
		ArrayList candidate = new ArrayList<>();
		for(int i =0;i> result = new ArrayList<>();
		ArrayList now = new ArrayList<>();
		permute(result, candidate, now);
		System.out.println("total num:"+result.size());
		for(int i=0;i> result2 = new ArrayList<>();
		ArrayList now2 = new ArrayList<>();
		combination(result2, candidate, now2);
		System.out.println("total num:"+result2.size());
		for(int i=0;i> result, ArrayList candidate, ArrayList now) {
		if(candidate.size()==1) {
			now.add(candidate.get(0));
			result.add(new ArrayList<>(now));
			now.remove(now.size()-1);
		} else {
			for(int i=0;i temp = new ArrayList<>();
				for(int j=0;j> result2, ArrayList candidate, ArrayList now) {
		for(int i=1;i<=candidate.size();i++) {
			combinationMain(result2, candidate, now, 0, i);
		}
	}
	
	private static void combinationMain(ArrayList> result2, ArrayList candidate, ArrayList now, int start, int length) {
		if(now.size()==length) {
			ArrayList tempResult = new ArrayList<>(now);
			result2.add(tempResult);
		} else if(start

4:最近邻点对

最邻近点对算法使用的是分治的策略,详情请查看https://www.geeksforgeeks.org/closest-pair-of-points-using-divide-and-conquer-algorithm/,下面是我的java版本,比较重要的一点就是,该算法的时间复杂度是O(nlgn)如下:

常用算法java汇总_第2张图片

其中需要说明的一点就是merge阶段,merge的时候需要从中间的区域找到最近的点对,看似需要n^2的时间复杂度,但是实际上,每个点周围需要比较的点实际上最多只有6个,因此时间复杂度实际上是O(n).

package Algorithm;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;

/*复杂度为O(nlogn)*/
public class ClosestPair {
	//比较器
	public static Comparator compareX = new Comparator() {

		@Override
		public int compare(node o1, node o2) {
			return o1.compareX(o1, o2);
		}
		
	};
	public static Comparator compareY = new Comparator() {

		@Override
		public int compare(node o1, node o2) {
			return o1.compareY(o1, o2);
		}
		
	};
	
	public static void main(String[] args) {
		node n1 = new node(2, 3);
		node n2 = new node(12, 30);
		node n3 = new node(40, 50);
		node n4 = new node(5, 1);
		node n5 = new node(12, 10);
		node n6 = new node(3, 4);
		node[] nodes = new node[] {n1, n2, n3, n4, n5, n6};
		double min = closest(nodes);
		System.out.println("closest distance is :"+min);
	}
	
	/*euclidean distance*/
	public static double dist(node o1, node o2) {
		return Math.sqrt(Math.pow(o1.x-o2.x, 2)+Math.pow(o1.y-o2.y, 2));
	}
	
	public static double closest(node[] nodes) {
		Arrays.sort(nodes, compareX);
		int end = nodes.length-1;
		int start = 0;
		return closestMain(nodes, start, end);
	}
	
	public static double closestStrip(ArrayList strip, double min) {
		double result = min;
		Collections.sort(strip, compareY);//这一步的意义在于保证每个点周围只有最多6个点用于比较
		int size = strip.size();
		for(int i=0;idr?dl:dr;
			ArrayList strip = new ArrayList<>();
			node midNode = nodes[mid];
			for(int i=start;i<=end;i++) {
				if(nodes[i].x-midNode.x-min<0.0000001) {
					strip.add(nodes[i]);
				}
			}
			return Math.min(min, closestStrip(strip, min));
		}
	}
}
class node{
	public int x;
	public int y;
	public node(int x, int y) {
		this.x = x;
		this.y = y;
	}
	public int compareX(node node1, node node2) {
		if(node1.x>=node1.x) {
			return 1;
		} else {
			return 0;
		}
	}
	
	public int compareY(node node1, node node2) {
		if(node1.y>=node1.y) {
			return 1;
		} else {
			return 0;
		}
	}
}

 

你可能感兴趣的:(面试)