Estructuras de datos y algoritmos

montón

1.1 Definición de montón

Un montón es un término general para un tipo especial de estructura de datos en informática. Un montón generalmente se puede considerar como un objeto de matriz de un árbol binario completo.

Características del montón:

  1. Es un árbol binario completo. Excepto que la última capa del árbol no necesita estar llena, todas las demás capas están llenas de izquierda a derecha. Si la última capa de nodos no está llena, entonces la izquierda y la derecha deben estar llenas. estar lleno.
    inserte la descripción de la imagen aquí

  2. Por lo general, se implementa con una matriz.
    El método específico es colocar los nodos del árbol binario en la matriz en orden jerárquico. El nodo raíz está en la posición 1, sus nodos secundarios están en las posiciones 2 y 3, y los nodos secundarios de los nodos secundarios están respectivamente en las posiciones 4, 5, 6 y 7, y así sucesivamente.
    inserte la descripción de la imagen aquí
    Si la posición de un nodo es k, la posición de su nodo principal es [k/2] y las posiciones de sus dos nodos secundarios son 2k y 2k+1 respectivamente. De esta manera, sin usar punteros, también podemos movernos hacia arriba y hacia abajo en el árbol calculando el índice de la matriz: desde a[k] hacia arriba un nivel, sea k igual a k/2, y haga k igual a 2k en el siguiente nivel O 2k+1.

  3. Cada nodo es mayor o igual que sus dos nodos secundarios. Cabe señalar aquí que el montón solo estipula que cada nodo es mayor o igual que sus dos nodos secundarios, pero no se especifica el orden de estos dos nodos secundarios, que es diferente del árbol de búsqueda binaria que aprendimos antes.

1.2 Diseño de la API del montón

inserte la descripción de la imagen aquí

1.3 Implementación del montón

1.3.1 Implementación del método de inserción

El montón utiliza una matriz para completar el almacenamiento de elementos de datos. Dado que la capa inferior de la matriz es una serie de direcciones de memoria continuas, queremos insertar datos en el montón. Solo podemos almacenar datos en la matriz a partir del índice 0, y luego almacenar datos secuencialmente. Sin embargo, se requiere el orden de los elementos en el montón. Los datos de cada nodo deben ser mayores o iguales que los datos de sus dos nodos secundarios, por lo que cada vez que se inserta un elemento, el orden de los los datos en el montón se desordenarán.. En este momento, necesitaremos alguna forma de colocar los datos recién insertados en el lugar correcto.
inserte la descripción de la imagen aquí
Por lo tanto, si se inserta un nuevo elemento en el montón, solo necesitamos comparar continuamente el tamaño del nuevo nodo a[k] y su nodo principal a[k/2], y luego completar el intercambio de elementos de datos de acuerdo con el resultado, y se puede completar Ajuste ordenado del montón.

1.3.2 Implementación del método de eliminación del elemento más grande delMax

Por las características del montón, podemos saber que el elemento en el índice 1, es decir, el nodo raíz es el elemento más grande. Cuando eliminamos el elemento del nodo raíz, es necesario que aparezca un nuevo nodo raíz. En este momento, podemos colocar temporalmente el último elemento en el montón en el índice 1 como el nodo raíz, pero es posible que no cumpla con los requisitos de ordenación del montón. En este momento, necesitamos usar algunos métodos para colocar este nuevo nodo raíz en un s adecuado posición.

inserte la descripción de la imagen aquí
Por lo tanto, después de eliminar el elemento más grande, solo necesita colocar el último elemento en el índice 1 y mantener presionado el nodo actual a[k] y sus nodos secundarios a[2k] y a[2k+1] El ajuste ordenado del el montón se puede completar intercambiando la posición del más grande.

1.3.3 Generación de implementación de almacenamiento dinámico

//堆代码
public class Heap<T extends Comparable<T>> {
    
    
	//存储堆中的元素
	private T[] items;
	//记录堆中元素的个数
	private int N;
	public Heap(int capacity) {
    
    
		items = (T[]) new Comparable[capacity+1];
		N=0;
	}
	//判断堆中索引i处的元素是否小于索引j处的元素
	private boolean less(int i,int j){
    
    
		return items[i].compareTo(items[j])<0;
	}
	//交换堆中i索引和j索引处的值
	private void exch(int i,int j){
    
    
		T tmp = items[i];
		items[i] = items[j];
		items[j] = tmp;
	}
	//往堆中插入一个元素
	public void insert(T t){
    
    
		items[++N] = t;
		swim(N);
	}
	//删除堆中最大的元素,并返回这个最大元素
	public T delMax(){
    
    
		T max = items[1];
		//交换索引1处和索引N处的值
		exch(1,N);
		//删除最后位置上的元素
		items[N]=null;
		N--;//个数-1
		sink(1);
		return max;
	}
	//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
	private void swim(int k){
    
    
		//如果已经到了根结点,就不需要循环了
		while(k>1){
    
    
			//比较当前结点和其父结点
			if(less(k/2,k)){
    
    
			//父结点小于当前结点,需要交换
			exch(k/2,k);
		}
		k = k/2;
		}
	}
	//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
	private void sink(int k){
    
    
		//如果当前已经是最底层了,就不需要循环了
		while(2*k<=N){
    
    
			//找到子结点中的较大者
			int max;
			if (2*k+1<=N){
    
    //存在右子结点
				if (less(2*k,2*k+1)){
    
    
					max = 2*k+1;
				}else{
    
    
					max = 2*k;
				}
			}else{
    
    //不存在右子结点
				max = 2*k;
			}
			//比较当前结点和子结点中的较大者,如果当前结点不小,则结束循环
			if (!less(k,max)){
    
    
			break;
		}
		//当前结点小,则交换,
		exch(k,max);
		k = max;
		}
	}
}

//测试代码
public class Test {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Heap<String> heap = new Heap<String>(20);
		heap.insert("S");
		heap.insert("G");
		heap.insert("I");
		heap.insert("E");
		heap.insert("N");
		heap.insert("H");
		heap.insert("O");
		heap.insert("A");
		heap.insert("T");
		heap.insert("P");
		heap.insert("R");
		String del;
		while((del=heap.delMax())!=null){
    
    
			System.out.print(del+",");
		}
	}
}

1.4 Clasificación de montón

Dada una matriz:

 String[] arr = {
    
    "S","O","R","T","E","X","A","M","P","L","E"}

Ordene los caracteres en la matriz de pequeños a grandes.

Pasos de implementación:

  1. montón de construcción;
  2. Obtenga el elemento superior del montón, este valor es el valor máximo;
  3. Intercambie el elemento superior del montón y el último elemento de la matriz, en este momento el elemento más grande de todos los elementos se ha colocado en una posición adecuada;
  4. Ajuste el montón y coloque el valor máximo de los elementos restantes excepto el último elemento en la parte superior del montón nuevamente;
  5. Repita los pasos 2 a 4 hasta que quede un elemento en el montón.

inserte la descripción de la imagen aquí

1.4.1 Proceso de construcción del montón

La idea más intuitiva de la construcción del montón es crear una nueva matriz y luego atravesar la matriz original de izquierda a derecha. Después de obtener cada elemento, se agrega a la nueva matriz y el montón se ajusta flotando arriba, y finalmente la nueva matriz Es solo un montón.

Aunque el método anterior es muy intuitivo y sencillo, podemos hacerlo de una manera más inteligente. Cree una nueva matriz, copie los datos de la matriz original 0~length-1en la nueva matriz 1~length, comience a escanear desde la mitad de la longitud de la nueva matriz hasta el índice 1 (de derecha a izquierda) y luego ajuste el hundimiento de cada elemento escaneado.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

1.4.2 Proceso de clasificación de almacenamiento dinámico

Para el montón construido, solo necesitamos realizar una operación de eliminación similar al montón para completar la clasificación.

  1. Intercambie el elemento superior del montón con el último elemento del montón;
  2. Ajuste el montón hundiendo el elemento superior del montón y coloque el elemento más grande en la parte superior del montón (en este momento, el último elemento no participa en el ajuste del montón, porque los datos más grandes han llegado al extremo derecho de la matriz)
  3. Repita los pasos 1 y 2 hasta que el último elemento permanezca en el montón.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
el código

//对排序代码
public class HeapSort {
    
    
	//对source数组中的数据从小到大排序
	public static void sort(Comparable[] source) {
    
    
		//1.创建一个比原数组大1的数组
		Comparable[] heap = new Comparable[source.length + 1];
		//2.构造堆
		createHeap(source,heap);
		//3.堆排序
		//3.1定义一个变量,记录heap中未排序的所有元素中最大的索引
		int N = heap.length-1;
		while(N!=1){
    
    
			//3.2交换heap中索引1处的元素和N处的元素
			exch(heap,1,N);
			N--;
			//3.3对索引1处的元素在0~N范围内做下沉操作
			sink(heap,1,N);
		}
		//4.heap中的数据已经有序,拷贝到source中
		System.arraycopy(heap,1,source,0,source.length);
	}
	
	//根据原数组source,构造出堆heap
	private static void createHeap(Comparable[] source, Comparable[] heap) {
    
    
		//1.把source中的数据拷贝到heap中,从heap的1索引处开始填充
		System.arraycopy(source,0,heap,1,source.length);
		//2.从heap索引的一半处开始倒叙遍历,对得到的每一个元素做下沉操作
		for (int i = (heap.length-1)/2; i>0 ; i--) {
    
    
			sink(heap,i,heap.length-1);
		}
	}
	//判断heap堆中索引i处的元素是否小于索引j处的元素
	private static boolean less(Comparable[] heap, int i, int j) {
    
    
		return heap[i].compareTo(heap[j])<0;
	}
	//交换heap堆中i索引和j索引处的值
	private static void exch(Comparable[] heap, int i, int j) {
    
    
		Comparable tmp = heap[i];
		heap[i] = heap[j];
		heap[j] = tmp;
	}
	//在heap堆中,对target处的元素做下沉,范围是0~range
	private static void sink(Comparable[] heap, int target, int range){
    
    
		//没有子结点了
		while (2*target<=range){
    
    
			//1.找出target结点的两个子结点中的较大值
			int max=2*target;
			if (2*target+1<=range){
    
    
				//存在右子结点
				if (less(heap,2*target,2*target+1)){
    
    
					max=2*target+1;
				}
			}
			//2.如果当前结点的值小于子结点中的较大值,则交换
			if(less(heap,target,max)){
    
    
				exch(heap,target,max);
			}
			//3.更新target的值
			target=max;
		}
	}
}

//测试代码
public class Test {
    
    
	public static void main(String[] args) throws Exception {
    
    
		String[] arr = {
    
    "S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};
		HeapSort.sort(arr);
		System.out.println(Arrays.toString(arr));
	}
}

Supongo que te gusta

Origin blog.csdn.net/qq_33417321/article/details/121996676
Recomendado
Clasificación