[C++] Buscar y ordenar

color naranja

Encontrar

árbol de clasificación binaria

Insertar descripción de la imagen aquí

Ejemplo de código

#include "stdio.h"    
#include "stdlib.h"   

#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */

typedef int Status;	/* Status是函数的类型,其值是函数结果状态代码,如OK等 */ 

/* 二叉树的二叉链表结点结构定义 */
typedef  struct BiTNode	/* 结点结构 */
{
    
    
	int data;	/* 结点数据 */
	struct BiTNode *lchild, *rchild;	/* 左右孩子指针 */
} BiTNode, *BiTree;


/* 递归查找二叉排序树T中是否存在key, */
/* 指针f指向T的双亲,其初始调用值为NULL */
/* 若查找成功,则指针p指向该数据元素结点,并返回TRUE */
/* 否则指针p指向查找路径上访问的最后一个结点并返回FALSE */
Status SearchBST(BiTree T, int key, BiTree f, BiTree *p) 
{
    
      
	if (!T)	/*  T为空,查找不成功,返回false */
	{
    
     
		*p = f;  
		return FALSE; 
	}
	else if (key==T->data) /*  查找成功 */
	{
    
     
		*p = T;  
		return TRUE; 
	} 
	else if (key<T->data) 
		return SearchBST(T->lchild, key, T, p);  /*  在左子树中继续查找 */
	else  
		return SearchBST(T->rchild, key, T, p);  /*  在右子树中继续查找 */
}


/*  当二叉排序树T中不存在关键字等于key的数据元素时, */
/*  插入key并返回TRUE,否则返回FALSE */
Status InsertBST(BiTree *T, int key) 
{
    
      
	BiTree p,s;
	if (!SearchBST(*T, key, NULL, &p)) /* 查找不成功,p是一个传出参数 */
	{
    
    
		s = (BiTree)malloc(sizeof(BiTNode));
		s->data = key;  
		s->lchild = s->rchild = NULL;  
		if (!p) 
			*T = s;			/*  插入s为新的根结点 */
		else if (key<p->data) 
			p->lchild = s;	/*  插入s为左孩子 */
		else 
			p->rchild = s;  /*  插入s为右孩子 */
		return TRUE;
	} 
	else 
		return FALSE;  /*  树中已有关键字相同的结点,不再插入 */
}

/* 从二叉排序树中删除结点p,并重接它的左或右子树。 */
Status Delete(BiTree *p)
{
    
    
	BiTree q,s;
	if((*p)->rchild==NULL) /* 右子树空则只需重接它的左子树(待删结点是叶子也走此分支) */
	{
    
    
		q=*p; *p=(*p)->lchild; free(q);
	}
	else if((*p)->lchild==NULL) /* 只需重接它的右子树 */
	{
    
    
		q=*p; *p=(*p)->rchild; free(q);
	}
	else /* 左右子树均不空 */
	{
    
    
		q=*p; s=(*p)->lchild;
		while(s->rchild) /* 转左,然后向右到尽头(找待删结点的前驱) */
		{
    
    
			q=s;
			s=s->rchild;
		}
		(*p)->data=s->data; /*  s指向被删结点的直接前驱(将被删结点前驱的值取代被删结点的值) */
		if(q!=*p)  //代表p的左节点有右子树,此时s在p的左节点的右子树最右边,不会有右节点了
			q->rchild=s->lchild; /*  重接q的右子树 */ 
		else //代表p的左节点没有右子树,此时s就是p的左节点,也是p的前驱。
			q->lchild=s->lchild; /*  重接q的左子树 */
		free(s);
	}
	return TRUE;
}

/* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点, */
/* 并返回TRUE;否则返回FALSE。 */
Status DeleteBST(BiTree *T,int key)
{
    
     
	if(!*T) /* 不存在关键字等于key的数据元素 */ 
		return FALSE;
	else
	{
    
    
		if (key==(*T)->data) /* 找到关键字等于key的数据元素 */ 
			return Delete(T);
		else if (key<(*T)->data)
			return DeleteBST(&(*T)->lchild,key);
		else
			return DeleteBST(&(*T)->rchild,key);
		 
	}
}

void ShowTree(BiTree t){
    
    
	if(t==NULL){
    
    
		return;
	}
	printf("%d ", t->data);
	ShowTree(t->lchild);
	ShowTree(t->rchild);
}

int main()
{
    
        
	int i;
	int a[10]={
    
    62,88,58,47,35,73,51,99,37,93};
	BiTree T=NULL;
	
	for(i=0;i<10;i++)
	{
    
    
		InsertBST(&T, a[i]);
	}
	ShowTree(T);
	printf("\n");
	DeleteBST(&T,47);
    printf("本样例建议断点跟踪查看二叉排序树结构");
	printf("\n");
	ShowTree(T);
	return 0;
}

Insertar descripción de la imagen aquí

Resumir

En resumen, el árbol de clasificación binaria se almacena de forma vinculada, lo que mantiene la ventaja de la estructura de almacenamiento vinculada de que no es necesario mover elementos al realizar operaciones de inserción o eliminación. Siempre que se encuentren las posiciones de inserción y eliminación adecuadas, el El puntero del enlace solo necesita ser modificado. El rendimiento temporal de la inserción y eliminación es relativamente bueno. Para buscar en un árbol de clasificación binario, se toma la ruta desde el nodo raíz hasta el nodo que se va a buscar y el número de comparaciones es igual al número de niveles del nodo con un valor dado en el árbol de clasificación binario. En casos extremos, es al menos una vez, es decir, el nodo raíz es el nodo que estás buscando y no excederá como máximo la profundidad del árbol. En otras palabras, el rendimiento de la búsqueda de un árbol de clasificación binario depende de la forma del árbol de clasificación binario. Pero el problema es que la forma del árbol de clasificación binario es incierta.

Por ejemplo, para una matriz como {62,88,58,47,35,73,51,99,37,93}, podemos construir un árbol de clasificación binario como se muestra en la siguiente figura. Pero si el orden de los elementos de la matriz es de pequeño a grande, como {35,37,47,51,58,62,73,88,93,99}, entonces el árbol de clasificación binario se convierte en un árbol sesgado en el extremo derecho. Nota: Sigue siendo un árbol binario, como se muestra a continuación a la derecha. En este momento, también estamos buscando el nodo 99. La imagen inferior izquierda solo necesita dos comparaciones, mientras que la imagen inferior derecha requiere 10 comparaciones para obtener el resultado. Hay una gran diferencia entre los dos.

Insertar descripción de la imagen aquí

En otras palabras, esperamos que el árbol de clasificación binaria esté relativamente equilibrado, es decir, su profundidad sea la misma que la del árbol binario completo, que es (logn) + 1. Entonces la complejidad del tiempo de búsqueda es O (logn), lo cual es aproximado a la mitad de la búsqueda. De hecho, arriba, la imagen superior izquierda tampoco está lo suficientemente equilibrada. Es obviamente pesada a la izquierda y liviana a la derecha.

El peor caso de desequilibrio es un árbol sesgado como el de la esquina superior derecha. La complejidad del tiempo de búsqueda es O (n), lo que equivale a una búsqueda secuencial.

Por lo tanto, si queremos buscar un conjunto según un árbol de clasificación binario, es mejor construirlo como un árbol de clasificación binario equilibrado. Esto nos lleva a otra pregunta: cómo equilibrar el árbol de clasificación binario.

Árbol binario equilibrado (árbol AVL)

Código

El código es bastante difícil de entender, puedes entenderlo junto con este blog: Comprensión de la estructura de datos del árbol AVL (árbol binario equilibrado)

#include "stdio.h"    
#include "stdlib.h"   

#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */

typedef int Status;	/* Status是函数的类型,其值是函数结果状态代码,如OK等 */ 


/* 二叉树的二叉链表结点结构定义 */
typedef  struct BiTNode	/* 结点结构 */
{
    
    
	int data;	/* 结点数据 */
	int bf; /*  结点的平衡因子,即结点的左子树高度减去右子树高度 */ 
	struct BiTNode *lchild, *rchild;	/* 左右孩子指针 */
} BiTNode, *BiTree;


/* 对以p为根的二叉排序树作右旋处理, */
/* 处理之后p指向新的树根结点,即旋转处理之前的左子树的根结点 */
void R_Rotate(BiTree *P)
{
    
     
	BiTree L;
	L=(*P)->lchild; /*  L指向P的左子树根结点 */ 
	(*P)->lchild=L->rchild; /*  L的右子树挂接为P的左子树 */ 
	L->rchild=(*P);
	*P=L; /*  P指向新的根结点 */ 
}

/* 对以P为根的二叉排序树作左旋处理, */
/* 处理之后P指向新的树根结点,即旋转处理之前的右子树的根结点0  */
void L_Rotate(BiTree *P)
{
    
     
	BiTree R;
	R=(*P)->rchild; /*  R指向P的右子树根结点 */ 
	(*P)->rchild=R->lchild; /* R的左子树挂接为P的右子树 */ 
	R->lchild=(*P);
	*P=R; /*  P指向新的根结点 */ 
}

#define LH +1 /*  左高 */ 
#define EH 0  /*  等高 */ 
#define RH -1 /*  右高 */ 

/*  对以指针T所指结点为根的二叉树作左平衡旋转处理 */
/*  本算法结束时,指针T指向新的根结点 */
void LeftBalance(BiTree *T)
{
    
     
	BiTree L,Lr;
	L=(*T)->lchild; /*  L指向T的左子树根结点 */ 
	switch(L->bf)
	{
    
     /*  检查T的左子树的平衡度,并作相应平衡处理 */ 
		 case LH: /*  新结点插入在T的左孩子的左子树上,要作单右旋处理 */ 
			(*T)->bf=L->bf=EH;
			R_Rotate(T);
			break;
		//L的右子树更高,即L的bf与T的bf值符号相反
		 case RH: /*  新结点插入在T的左孩子的右子树上,要作双旋处理 */ 
			Lr=L->rchild; /*  Lr指向T的左孩子的右子树根 */ 
			switch(Lr->bf)
			{
    
     /*  修改T及其左孩子的平衡因子 */ 
				case LH: (*T)->bf=RH;
						 L->bf=EH;
						 break;
				case EH: (*T)->bf=L->bf=EH;
						 break;
				case RH: (*T)->bf=EH;
						 L->bf=LH;
						 break;
			}
			Lr->bf=EH;
			L_Rotate(&(*T)->lchild); /*  对T的左子树作左旋平衡处理 */ 
			R_Rotate(T); /*  对T作右旋平衡处理 */ 
	}
}

/*  对以指针T所指结点为根的二叉树作右平衡旋转处理, */ 
/*  本算法结束时,指针T指向新的根结点 */ 
void RightBalance(BiTree *T)
{
    
     
	BiTree R,Rl;
	R=(*T)->rchild; /*  R指向T的右子树根结点 */ 
	switch(R->bf)
	{
    
     /*  检查T的右子树的平衡度,并作相应平衡处理 */ 
	 case RH: /*  新结点插入在T的右孩子的右子树上,要作单左旋处理 */ 
			  (*T)->bf=R->bf=EH;
			  L_Rotate(T);
			  break;
	 case LH: /*  新结点插入在T的右孩子的左子树上,要作双旋处理 */ 
			  Rl=R->lchild; 			/*  Rl指向T的右孩子的左子树根 */ 
			  switch(Rl->bf)
			  {
    
     						/*  修改T及其右孩子的平衡因子 */ 
				case RH: (*T)->bf=LH;
						 R->bf=EH;
						 break;
				case EH: (*T)->bf=R->bf=EH;
						 break;
				case LH: (*T)->bf=EH;
						 R->bf=RH;
						 break;
			  }
			  Rl->bf=EH;
			  R_Rotate(&(*T)->rchild); /*  对T的右子树作右旋平衡处理 */ 
			  L_Rotate(T); /*  对T作左旋平衡处理 */ 
	}
}

/*  若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个 */ 
/*  数据元素为e的新结点,并返回1,否则返回0。若因插入而使二叉排序树 */ 
/*  失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。 */
Status InsertAVL(BiTree *T,int e,Status *taller)
{
    
      
	if(!*T)//如果是一棵空树
	{
    
     /*  插入新结点,树“长高”,置taller为TRUE */ 
		 *T=(BiTree)malloc(sizeof(BiTNode));
		 (*T)->data=e; (*T)->lchild=(*T)->rchild=NULL; (*T)->bf=EH;
		 *taller=TRUE;
	}
	else
	{
    
    
		if (e==(*T)->data)
		{
    
     /*  树中已存在和e有相同关键字的结点则不再插入 */ 
			*taller=FALSE; return FALSE;
		}
		if (e<(*T)->data)
		{
    
     /*  应继续在T的左子树中进行搜索 */ 
			if(!InsertAVL(&(*T)->lchild,e,taller)) /*  返回结果为false,未插入 */ 
				return FALSE;
			if(*taller) /*   已插入到T的左子树中且左子树“长高” */ 
				switch((*T)->bf) /*  检查T的平衡度 */ 
				{
    
    
					case LH: /*  原本左子树比右子树高,需要作左平衡处理 */ 
							LeftBalance(T);	*taller=FALSE; break;
					case EH: /*  原本左、右子树等高,现因左子树增高而使树增高 */ 
							(*T)->bf=LH; *taller=TRUE; break;
					case RH: /*  原本右子树比左子树高,现左、右子树等高 */  
							(*T)->bf=EH; *taller=FALSE; break;
				}
		}
		else
		{
    
     /*  应继续在T的右子树中进行搜索 */ 
			if(!InsertAVL(&(*T)->rchild,e,taller)) /*  未插入 */ 
				return FALSE;
			if(*taller) /*  已插入到T的右子树且右子树“长高” */ 
				switch((*T)->bf) /*  检查T的平衡度 */ 
				{
    
    
					case LH: /*  原本左子树比右子树高,现左、右子树等高 */ 
							(*T)->bf=EH; *taller=FALSE;	break;
					case EH: /*  原本左、右子树等高,现因右子树增高而使树增高  */
							(*T)->bf=RH; *taller=TRUE; break;
					case RH: /*  原本右子树比左子树高,需要作右平衡处理 */ 
							RightBalance(T); *taller=FALSE; break;
				}
		}
	}
	return TRUE;
}

int main(void)
{
    
        
	int i;
	int a[10]={
    
    3,2,1,4,5,6,7,10,9,8};
	BiTree T=NULL;
	Status taller;
	for(i=0;i<10;i++)
	{
    
    
		InsertAVL(&T,a[i],&taller);
	}
	printf("本样例建议断点跟踪查看平衡二叉树结构");
	return 0;
}

tabla de picadillo

Código

En este fragmento de código, hay tres funciones: inicialización, inserción y búsqueda. En este código, clave es el valor clave del valor que desea encontrar, H->elem[clave] es el valor que desea encontrar y la dirección del valor que desea encontrar es el valor de índice de la matriz.

#include "stdio.h"    
#include "stdlib.h"   

#define MAXSIZE 100 /* 存储空间初始分配量 */

#define SUCCESS 1
#define UNSUCCESS 0
#define HASHSIZE 12 /* 定义散列表长为数组的长度 */
#define NULLKEY -32768 

typedef int Status;	/* Status是函数的类型,其值是函数结果状态代码,如OK等 */ 

typedef struct
{
    
    
   int *elem; /* 数据元素存储基址,动态分配数组 */
   int count; /*  当前数据元素个数 */
}HashTable;

int m=0; /* 散列表表长,全局变量 */

/* 初始化散列表 */
Status InitHashTable(HashTable *H)
{
    
    
	int i;
	m=HASHSIZE;
	H->elem = (int *)malloc(sizeof(int) * m);
	for (i = 0; i < m;i++){
    
    
		H->elem[i] = NULLKEY;
	}
	return SUCCESS;
}

/* 散列函数 */
int Hash(int key)
{
    
    
	return key % m; /* 除留余数法 */
}

/* 插入关键字进散列表 */
void InsertHash(HashTable *H,int key)
{
    
    
	int addr = Hash(key);
	while(H->elem[addr]!=NULLKEY){
    
    
		addr = (addr+1)%m;
	}
	H->elem[addr] = key;
}

/* 散列表查找关键字 */
Status SearchHash(HashTable H,int key,int *addr)
{
    
    
	*addr = Hash(key);  /* 求散列地址 */
	while(H.elem[*addr] != key) /* 如果不为空,则冲突 */
	{
    
    
		*addr = (*addr+1) % m; /* 开放定址法的线性探测 */
		if (H.elem[*addr] == NULLKEY || *addr == Hash(key)) /* 如果循环回到原点 */
			return UNSUCCESS;	/* 则说明关键字不存在 */
	}
	return SUCCESS;
}

int main()
{
    
    
	int arr[HASHSIZE]={
    
    12,67,56,16,25,37,22,29,15,47,48,34};
	int i,p,key,result;
	HashTable H;

	key=39;

	InitHashTable(&H);
	for(i=0;i<m;i++)
		 InsertHash(&H,arr[i]);
	
	result=SearchHash(H,key,&p);
	if (result)
		printf("查找 %d 的地址为:%d \n",key,p);
	else
		printf("查找 %d 失败。\n",key);

	for(i=0;i<m;i++)
	{
    
    
		key=arr[i];
		SearchHash(H,key,&p);
		printf("查找 %d 的地址为:%d \n",key,p);
	}

	return 0;
}

Insertar descripción de la imagen aquí

clasificar

ordenamiento de burbuja

Tipo estándar

i en la línea 14 registra el valor del índice que se ha ordenado, por lo que j> = i en la línea 15. En este momento, los valores antes de i ya están ordenados en secuencia, por lo que no es necesario volver a tomar fotografías.

#include<iostream>
using namespace std;
void swap(int* a,int i,int j){
    
    
	int temp;
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

int main(){
    
    
	int a[] = {
    
    9,1,5,8,3,7,4,6,2};
	int len=sizeof(a)/sizeof(a[0]);

	for (int i = 0; i < len;i++){
    
    
		for (int j = len - 2; j >= i;j--){
    
    
			if(a[j]>a[j+1]){
    
    
				swap(a, j, j + 1);
			}
		}
	}
	for (int i = 0; i < len;i++){
    
    
		cout << a[i];
	}
		
	return 0;
}

Insertar descripción de la imagen aquí

Mejorado

Se agrega una variable de marca y se inicializa en verdadero. Si no se produce ningún intercambio durante una determinada clasificación, es decir, la bandera siempre es falsa, lo que significa que la matriz ya está en orden y no es necesario realizar juicios de bucle sin sentido.

#include<iostream>
using namespace std;
void swap(int* a,int i,int j){
    
    
	int temp;
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

int main(){
    
    
	int a[] = {
    
    9,1,5,8,3,7,4,6,2};
	int len=sizeof(a)/sizeof(a[0]);
    int flag = true;
    for (int i = 0; i < len&&true;i++){
    
    
        flag = false;
        for (int j = len - 2; j >= i;j--){
    
    
			if(a[j]>a[j+1]){
    
    
				swap(a, j, j + 1);
                flag = true;
            }
		}
	}
	for (int i = 0; i < len;i++){
    
    
		cout << a[i];
	}
		
	return 0;
}

Insertar descripción de la imagen aquí

Orden de selección simple

La característica más importante de esta clasificación es que la cantidad de intercambios de datos móviles es pequeña, lo que ahorra el tiempo correspondiente. La complejidad del tiempo total sigue siendo O (n 2 ) como el método de clasificación de burbujas , pero el rendimiento de la clasificación de selección simple sigue siendo ligeramente mejor que el de la clasificación de burbujas.

Es equivalente a establecer un índice del valor mínimo del registro de variable, y luego, después del final del recorrido del bucle j, se juzga que si i! = min, significa que i no es el índice del valor mínimo, intercambio.

#include<iostream>
using namespace std;
void swap(int* a,int i,int j){
    
    
	int temp;
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

int main(){
    
    
	int a[] = {
    
    9,1,5,8,3,7,4,6,2};
	int len=sizeof(a)/sizeof(a[0]);
    
    for (int i = 0; i < len-1;i++){
    
    
        int min = i;
        for (int j = i+1; j <len;j++){
    
    
			if(a[j]<a[min]){
    
    
                min = j;
            }
		}
        swap(a, i, min);
    }
	for (int i = 0; i < len;i++){
    
    
		cout << a[i];
	}
		
	return 0;
}

Insertar descripción de la imagen aquí

algoritmo de clasificación por inserción directa

Para explicar la función InsertSort, en primer lugar, el primer nivel del bucle for comienza desde 1, es decir, suponiendo que se ha colocado un [0], los elementos posteriores no son más que una cuestión de decidir si insertarlo en el lado izquierdo o derecho. Luego comience a comparar a[i-1] (el último elemento que se ha colocado) > a[i]. De hecho, es para juzgar el último elemento que se ha colocado y el primer elemento que aún no se ha colocado. tamaño de.

Si a[i] es más grande, significa que a[i] debe colocarse en el lado derecho de a[i-1], eso es correcto, no es necesario moverse.

Si a [i-1] es más grande, significa que a [i] debe colocarse en el lado izquierdo de a [i-1], en este momento use temp para registrar el valor de a [i] y use el segundo bucle for para ordenar los elementos de la matriz ordenados previamente se desplazan una posición hacia la derecha hasta que el índice j=-1 (lo que significa que temp es más pequeño que todos los elementos de la matriz ordenados actualmente, por lo que se coloca en el extremo izquierdo) o se encuentra a[j] <=temp, entonces temp se puede colocar en la posición de a[j+1].

En todo el código, a[j+1] siempre representa una posición vacía, porque el valor en el primer j+1 ha sido registrado por temp, y los siguientes se desplazan hacia la derecha en secuencia.

#include<iostream>
using namespace std;
void swap(int* a,int i,int j){
    
    
	int temp;
	temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

void InsertSort(int* a,int len){
    
    
    int temp,j;
    for (int i = 1; i < len;i++){
    
    
        
        if(a[i-1]>a[i]){
    
    
            //temp存储了a[i]的值,那么此时a[i]就相当于空了
            //此时我们需要把i之前大于temp的值统统向后移动一个位置
            temp = a[i];
            for (j = i - 1; a[j] > temp&&j>=0;j--){
    
    
                a[j + 1] = a[j];
            }
            a[j + 1] = temp;
        }
    }
}

int main(){
    
    
	int a[] = {
    
    9,1,5,8,3,7,4,6,2};
    // int a[] = {4,3,6,2,9,1,0};
    int len=sizeof(a)/sizeof(a[0]); 
    InsertSort(a,len);
    for (int i = 0; i < len;i++){
    
    
		cout << a[i];
	}
		
	return 0;
}

La complejidad temporal del algoritmo de ordenación por inserción directa es O (n 2 ), pero su rendimiento es ligeramente mejor que los dos primeros.

clasificación de montón

a = {5, 43, 14, 66, 34, 25},
Insertar descripción de la imagen aquí

#include<iostream>
using namespace std;

void swap(int a[],int begin,int end){
    
    
    int temp = a[begin];
    a[begin] = a[end];
    a[end] = temp;
}

//传入的s为要调整的节点,使得以s为根节点的树变成一个大顶堆
void heapadjust(int a[],int s,int m){
    
    
    int temp = a[s];
    int j;
    for (j = 2 * s; j <= m;j*=2){
    
    
    	//2*s为s的左节点,2*s+1为s的右节点,这里是找到以s为双亲结点的左右节点的最大值,其在数组中的下表为j
        if(j+1<=m&&a[j]<a[j+1]){
    
    
            j++;
        }
        //开始判断左右节点的最大值是否大于其双亲结点,如果不大于的话,那么就直接跳出循环
        //为什么可以直接跳出去呢?即使该节点的左右节点没有大于该节点的,但该节点的左右节点下面的节点有可能有大于的啊
        //因为heapsort()在第一个for循环中最先调用heapadjust()去调整的是a[0] / 2节点,堆具有完全二叉树的所有性质,所以
        //a[0] / 2节点其实就是最后一个非叶节点,对照上面的图就是30,然后再从右往左、从下往上,对每一个非叶节点调用
        //heapadjust()函数进行堆排序,使得其该节点的值大于左右两个子节点。因此在heapsort()第一个for循环后,数组第
        //一个值最大。将第一个(也就是确定好的最大值)放在最后面(也就是与最后面的元素交换)
        if(temp>=a[j]){
    
    
            break;
        }
        a[s] = a[j];
        s = j;//只要还在for循环内,就说明寻找的节点s的子节点j比s更大,此时我们要调整的就是j,看它的子节点是否有大于它的值。
    }
    a[s] = temp;
}

void heapsort(int a[]){
    
    
    for (int i = a[0] / 2; i >= 1;i--){
    
    
        heapadjust(a, i, a[0]);
    }
    //为什么j>1?因为下面每次循环都是把第一个(也是最大值)与最后的值交换,再调整使第一个为最大值
    for (int j = a[0]; j > 1;j--){
    
    
        swap(a, 1, j);
        heapadjust(a, 1, j - 1);
    }
}

int main(){
    
    
    int a[] = {
    
    9,50, 10, 90, 30, 70, 40,80,60,20};
    heapsort(a);
    for (int i = 1; i <= a[0];i++){
    
    
        cout << a[i]<<endl;
    }      
}

Insertar descripción de la imagen aquí
La complejidad temporal de la clasificación del montón es O (nlogn). No adecuado para situaciones en las que el número de secuencias a ordenar es relativamente pequeño

Ordenación rápida

template<typename keyname>
void swap(keyname &a,int begin,int end){
    
    
    int temp = a[begin];
    a[begin] = a[end];
    a[end] = temp;
}


/* 快速排序优化算法 */
template<typename keyname>
int Partition1(keyname &a,int low,int high)
{
    
     
	int pivotkey;
	
	
	pivotkey=a[low]; /* 用子表的第一个记录作枢轴记录 */
	int temp=pivotkey;  /* 将枢轴关键字备份到temp */
	while(low<high) /*  从表的两端交替地向中间扫描 */
	{
    
     
		 while(low<high&&a[high]>=pivotkey)
			high--;
		 a[low]=a[high];
		 while(low<high&&a[low]<=pivotkey)
			low++;
		 a[high]=a[low];
	}
	a[low]=temp;
	return low; /* 返回枢轴所在位置 */
}

template<typename keyname>
void QSort1(keyname &a,int low,int high)
{
    
     
	int pivot;
	
	pivot=Partition1(a,low,high); /*  将a[low..high]一分为二,算出枢轴值pivot */
    if(low<pivot-1)//加if判断是为了避免陷入死循环
	    QSort1(a,low,pivot-1);
    if(pivot-1<high)		/*  对低子表递归排序 */
	    QSort1(a,pivot+1,high);		/*  对高子表递归排序 */
	
}

int main(){
    
    
    vector<int>a={
    
    50,10,90,30,70,80,60,20};
    int len = a.size();
    QSort1(a, 0,len-1);
    for (int i = 0; i < len;i++){
    
    
         cout << a[i] << endl;
    }
}

Insertar descripción de la imagen aquí
La complejidad del tiempo es O (nlogn). En promedio, la complejidad del espacio también es O (logn).

Supongo que te gusta

Origin blog.csdn.net/mhyasadj/article/details/131973864
Recomendado
Clasificación