All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.utils.QuickSelect Maven / Gradle / Ivy

There is a newer version: 1.12.1
Show newest version
/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.badlogic.gdx.utils;

import java.util.Comparator;

/** Implementation of Tony Hoare's quickselect algorithm. Running time is generally O(n), but worst case is O(n^2) Pivot choice is
 * median of three method, providing better performance than a random pivot for partially sorted data.
 * http://en.wikipedia.org/wiki/Quickselect
 * @author Jon Renner */
public class QuickSelect {
	private T[] array;
	private Comparator comp;

	public int select (T[] items, Comparator comp, int n, int size) {
		this.array = items;
		this.comp = comp;
		return recursiveSelect(0, size - 1, n);
	}

	private int partition (int left, int right, int pivot) {
		T pivotValue = array[pivot];
		swap(right, pivot);
		int storage = left;
		for (int i = left; i < right; i++) {
			if (comp.compare(array[i], pivotValue) < 0) {
				swap(storage, i);
				storage++;
			}
		}
		swap(right, storage);
		return storage;
	}

	private int recursiveSelect (int left, int right, int k) {
		if (left == right) return left;
		int pivotIndex = medianOfThreePivot(left, right);
		int pivotNewIndex = partition(left, right, pivotIndex);
		int pivotDist = (pivotNewIndex - left) + 1;
		int result;
		if (pivotDist == k) {
			result = pivotNewIndex;
		} else if (k < pivotDist) {
			result = recursiveSelect(left, pivotNewIndex - 1, k);
		} else {
			result = recursiveSelect(pivotNewIndex + 1, right, k - pivotDist);
		}
		return result;
	}

	/** Median of Three has the potential to outperform a random pivot, especially for partially sorted arrays */
	private int medianOfThreePivot (int leftIdx, int rightIdx) {
		T left = array[leftIdx];
		int midIdx = (leftIdx + rightIdx) / 2;
		T mid = array[midIdx];
		T right = array[rightIdx];

		// spaghetti median of three algorithm
		// does at most 3 comparisons
		if (comp.compare(left, mid) > 0) {
			if (comp.compare(mid, right) > 0) {
				return midIdx;
			} else if (comp.compare(left, right) > 0) {
				return rightIdx;
			} else {
				return leftIdx;
			}
		} else {
			if (comp.compare(left, right) > 0) {
				return leftIdx;
			} else if (comp.compare(mid, right) > 0) {
				return rightIdx;
			} else {
				return midIdx;
			}
		}
	}

	private void swap (int left, int right) {
		T tmp = array[left];
		array[left] = array[right];
		array[right] = tmp;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy