El principio de implementación subyacente de la matriz PHP

La matriz es un tipo de datos muy potente y flexible en PHP. A diferencia de los lenguajes estáticos como Java y C, no necesitamos especificar el tamaño y el tipo de datos almacenados al inicializar una matriz PHP. Podemos usar indexación numérica al asignar valores. Por índice de cadena:

En función de las potentes funciones de las matrices PHP, podemos implementar fácilmente estructuras de datos más complejas, como pilas, colas, listas, colecciones, diccionarios, etc. La razón por la que las matrices PHP son tan poderosas es que se basan en tablas hash.

Estructura de datos subyacente de la matriz PHP

La estructura de datos subyacente de la tabla hash de las matrices PHP se define de la siguiente manera (ubicada Zend/zend_types.h):

Hay muchos miembros en esta tabla hash, elegimos algunos más importantes para hablar:

  • arData: Una matriz de elementos de almacenamiento almacenados en una tabla hash, cuya memoria es continua y arDataapunta a la posición inicial de la matriz;
  • nTableSize: La capacidad total de la matriz, es decir, arDatala cantidad de elementos que se pueden acomodar, el tamaño de la memoria se determina de acuerdo con este valor, su tamaño es la potencia de 2, el mínimo es 8 y luego aumenta en el orden de 8, 16, 32 ... ;
  • nTableMask: Este valor es la función hash cuando se usa el mapeo de elemento basado en un valor hash de la clave, que es el valor real nTableSizede la negativa, es decir nTableMask = -nTableSize, está representado por operación de bit nTableMask = ~nTableSize + 1;
  • nNumUsed, nNumOfElements: nNumUsedSe utiliza actualmente índice del grupo Bucketnúmero, pero no el número de elementos de la matriz válida, porque después de ciertos elementos de la matriz se eliminan y no inmediatamente retirados de la matriz, pero marcados IS_UNDEFsolamente en caso de una expansión de array hará realidad suprimido, nNumOfElementsesto significa que el número efectivo de elementos de la matriz, que llama al countvalor de retorno de función, si no hay expansión, nNumUsedha sido gradual, ya sea o no eliminar elementos;
  • nNextFreeElement: Esto es para determinar automáticamente, a partir de cero por defecto, tal como el uso del valor del índice $arr[] = 200, el tiempo de nNextFreeElementvalor se incrementa automáticamente por 1;
  • pDestructor: Al eliminar o sobrescribir un elemento en la matriz, si se proporciona este identificador de función, se llama a esta función al eliminar o sobrescribir para limpiar el elemento antiguo;
  • u: Esta estructura de consorcio se utiliza principalmente para algunas funciones auxiliares.

BucketLa estructura es relativamente simple, utiliza principalmente para guardar los elementos keyy value, y h (un valor hash, el valor hash o llamadas) es un número entero: Si el elemento es un valor de índice, su valor es el valor de los valores de índice; si la cadena es índice, este valor es keypor Time33el cálculo de un valor hash obtenido por el algoritmo, hlos valores de correlación para las ubicaciones de almacenamiento de elemento final. BucketLa estructura de datos es la siguiente:

Implementación básica de matriz PHP

La tabla hash se compone principalmente de dos partes: matriz de elementos de almacenamiento, función hash. La implementación básica de la tabla hash se ha discutido en el algoritmo anterior. Además de las características básicas de la tabla hash, la matriz en PHP tiene un lugar especial, es decir, está ordenada (a diferencia de HashMap en Java. El orden es diferente): el orden de los elementos en la matriz es el mismo que el orden de inserción. ¿Cómo se logra esto?

Para lograr el orden de las matrices PHP, la tabla hash subyacente de PHP agrega una capa de tabla de mapeo entre la función hash y la matriz de elementos. Esta tabla de mapeo también es una matriz. El tamaño es el mismo que la matriz de elementos almacenados. El tipo de elementos almacenados es Tipo entero, utilizado para guardar el subíndice del elemento en la matriz ordenada realmente almacenada: los elementos se insertan en la matriz de almacenamiento real en orden, y luego el subíndice de la matriz se almacena en la posición recién agregada de acuerdo con la lista hash de la función hash En la tabla de mapeo:

De esta forma, se puede completar el orden de los datos finales almacenados.

PHP matriz subestructura no se identifica de forma explícita en el mapa intermedio, pero con arDataponer juntos, en el momento de la inicialización de la matriz de memoria asignada para no sólo Bucketla memoria, sino también asignar la misma cantidad de uint32_tespacio, que dos espacio se asigna juntos, y luego arDatase desplazó a los elementos de almacenamiento de posición de una matriz, y este intermedio puede asignar por arDatael acceso a la hacia adelante.

Inicialización de matriz

Inicializar la matriz está dirigido principalmente a HashTableestablecer miembro, inicialización y no asigna inmediatamente arDatala memoria, después de insertar el primer elemento asignará arDatamemoria. operación de inicialización por zend_hash_initel macro está terminado, y finalmente por el _zend_hash_init_intprocesamiento de la función (la función se define en el Zend/zend_hash.carchivo):

En este momento, HashTablesólo el valor inicial se establece y el tamaño de la lista de hash de otros miembros, no se puede utilizar para elementos de la tienda.

Insertar datos

cuando inserto comprueba si la matriz se ha asignado espacio de almacenamiento, ya que la inicialización en realidad no asigna arDatamemoria, la primera vez que se inserta de acuerdo con nTableSizeel tamaño de la asignada después de la asignación se HashTable->u.flagspuede marcar con HASH_FLAG_INITIALIZEDuna máscara, por lo que la próxima vez cuando ya el parte movible encontrado distribución la operación no se repetirá, se encuentra en esta lógica de verificación de _zend_hash_add_or_update_ila función:

if (UNEXPECTED(!(HT_FLAGS(ht) & HASH_FLAG_INITIALIZED))) {
    zend_hash_real_init_mixed(ht);
    if (!ZSTR_IS_INTERNED(key)) {
        zend_string_addref(key);
        HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
        zend_string_hash_val(key);
    }
    goto add_to_hash;
}

Si arDatano tiene asignado, y en última instancia por zend_hash_real_init_mixed_exla asignación de memoria al completo:

Después de la asignación de arDatamemoria se puede insertar después de la operación, el primer elemento de inserción se inserta en orden arData, y luego en la arDatamatriz de almacenamiento de posición de acuerdo con un keyvalor de hash de nTableMaskuna posición correspondiente del mapa intermedio calculado en:

justo por encima El procesamiento de inserción más básico no implica la sobrescritura y limpieza de datos existentes.

Colisión de hash

La tabla hash en la parte inferior de la matriz PHP utiliza el método de dirección de cadena para resolver el conflicto hash, y los cubos en conflicto están conectados a una lista vinculada.

HashTableLos Bucketregistros en conflicto con los elementos de su arDataposición en la matriz, que no está en una posición a la lista, el elemento de conflicto guardar Bucketestructura, sino que se almacena en los elementos de almacenamiento zvalde u2la estructura, es decir Bucket.val.u2.next, se inserta en dos pasos:

// 将映射表中原来的值保存到新 Bucket 中,哈希冲突时会用到(以链表方式解决哈希冲突)
Z_NEXT(p->val) = HT_HASH_EX(arData, nIndex);
// 再把新元素数组存储位置更新到数据表中
// 保存idx:((unit32_t*))(ht->arData)[nIndex] = idx
HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx);

Búsqueda de matriz

Borrar HashTabledespués de la solución y lograr la colisión de hash, el proceso de búsqueda es relativamente simple: El primer keyvalor hash calculado nTableMaskpara dar un cálculo valor hash definitiva nIndex, y luego obtenido de una tabla de asignación de elemento de almacenamiento intermedio en base al valor de hash en la posición de almacenamiento de la matriz ordenada idx, a continuación, de acuerdo con idxla matriz ordenada de almacenamiento (es decir, arDataretirada) y Bucket, atravesado Bucket, la determinación Bucketde keysi para tener en cuenta key, si el recorrido termina, de lo contrario continuar de acuerdo con zval.u2.nextel recorrido de comparación.

El código fuente subyacente correspondiente es el siguiente:

https://qcdn.xueyuanjun.com/storage/uploads/images/gallery/2019-10/scaled-1680-/2ce1bc0c91ff172f451d8fb8cae16c38adc8202c5d976f87888869086cbabd62.jpg

Eliminar datos

Acerca de la matriz de datos borrados anteriormente se introduce la tabla de dispersión nNumUsedy nNumOfElementsse han mencionado en el campo, cuando se quita elementos de una matriz, que en realidad no extraiga y vuelva rehash, pero cuando arDatadespués de la plena, eliminará los datos innecesarios Para mejorar el rendimiento. Eso realmente se necesita capacidad de la matriz de eliminación en el caso de elementos: En primer lugar comprobar la proporción de elementos de la matriz se ha eliminado, si la relación llega a un valor umbral de la operación para reconstruir el índice se dispara, habrá eliminado este proceso Bucketpara eliminar, y luego poner de nuevo los Buckethuecos de relleno movimiento hacia adelante, si no se ha alcanzado el valor umbral serán asignados una nueva matriz 2 veces el tamaño original de la matriz, y los elementos de la matriz original copiado en la nueva matriz, y finalmente reconstruir el índice, el índice se eliminarán reconstruir Bucketcambio Excepto

El código subyacente correspondiente es el siguiente:

Además, hay muchas otras operaciones de matriz, como copiar, fusionar, destruir, reinicio, etc., el código correspondiente a estas operaciones se encuentran zend_hash.cen, los estudiantes interesados pueden ir a ver.

Supongo que te gusta

Origin www.cnblogs.com/stringarray/p/12717133.html
Recomendado
Clasificación