Clasificación de las calificaciones de los estudiantes en lenguaje C (clasificación de selección simple y clasificación de montón)

1. Clasificación de selección

La idea básica del ordenamiento por selección es: cada pasada (como la i-ésima pasada) selecciona el elemento con la clave más pequeña entre los siguientes n-i+1 (i=1,2...,n-1) elementos a clasificar, como un elemento ordenado El i-ésimo elemento de la subsecuencia, hasta que se complete el n-1º paso, solo hay un elemento para clasificar, por lo que no es necesario volver a elegir. El algoritmo de clasificación de montón en la clasificación de selección es el foco del examen a lo largo de los años.

2. Clasificación de selección simple

1. Pensamiento algorítmico

De acuerdo con la idea de clasificación de selección anterior, la idea del algoritmo de clasificación de selección simple se puede derivar intuitivamente: asumiendo que la tabla de clasificación es [L...n], la i-ésima clasificación es seleccionar el elemento con la clave más pequeña de Li.n] e I(i) Exchange, cada clasificación puede determinar la posición final de un elemento, de modo que toda la tabla de clasificación se puede ordenar después de la clasificación n-1.

2. Implementación del algoritmo

//简单选择排序
void selectsort(SqList &L){
    
    
	for(int i=0;i<L.length-1;i++){
    
          //一共进行n-1趟
		Elemtype min=L.data[i];        //记录最小的元素位置
		int n=0;
		for(int j=i+1;j<L.length;j++){
    
      //从未排序部分开始遍历
			if(L.data[j].grade<min.grade) {
    
    
				min=L.data[j];
				n=j;
			}
		}
		if(min.grade!=L.data[i].grade){
    
    
			Elemtype temp=L.data[i];
			L.data[i]=L.data[n];
			L.data[n]=temp;
		}
	}
}

3. Análisis de eficiencia

El análisis de rendimiento del algoritmo de clasificación de selección simple es el siguiente:

  • Eficiencia espacial: Solo se utiliza un número constante de unidades auxiliares, por lo que la eficiencia espacial es 0(1). ,
  • Eficiencia de tiempo: no es difícil ver del pseudocódigo anterior que en el proceso de selección y clasificación simple, el número de operaciones de movimiento de elementos es muy pequeño, no más de 3 (n-1) veces, y el mejor caso es moverse 0 veces, en este momento la lista correspondiente ya está ordenada, pero el número de comparaciones entre elementos no tiene nada que ver con el estado inicial de la secuencia, siempre es n(n- 1)/2 veces , por lo que la complejidad del tiempo siempre es 0(n 2 ) .
  • Estabilidad: después de encontrar el elemento mínimo en el paso i-ésimo, el intercambio con el elemento i-ésimo puede hacer que cambie la posición relativa del elemento i-ésimo y el elemento que contiene la misma palabra clave. Por ejemplo, la tabla L={2, 2,1 }, después de clasificar L={1, 2,2 }, la secuencia de clasificación final también es L={1,2,2}, obviamente, el orden relativo de 2 y 2 ha cambiado. Por lo tanto, la ordenación por selección simple es un método de ordenación inestable .

3. Ordenar montones

1. Pensamiento algorítmico

La idea de la clasificación de montones es muy simple: primero, los n elementos almacenados en L1...n] se integran en un montón inicial. Debido a las características del montón en sí (tome el montón superior grande como ejemplo), el elemento superior del montón es el valor máximo. Después de generar el elemento superior del montón, el elemento inferior del montón generalmente se envía a la parte superior del montón. En este momento, el nodo raíz no satisface la naturaleza del montón superior y el montón se destruye. Ajustar el elemento superior del montón hacia abajo para que pueda continuar manteniendo la naturaleza del montón superior y, a continuación, generar el elemento superior del montón. Repita esto hasta que solo quede un elemento en el montón. Se puede ver que la clasificación del montón necesita resolver dos problemas: ①¿Cómo construir una secuencia desordenada en un montón inicial? ②Después de generar el elemento superior del montón, ¿cómo ajustar los elementos restantes en un nuevo montón?

La clave para ordenar el montón es construir el montón inicial. En un árbol binario completo de n nodos, el último nodo es un hijo del nodo Ln/2'th. Filtre el subárbol cuya raíz es el nodo Ln/2'th (para un montón raíz grande, si la clave del nodo raíz es más pequeña que el que tiene la clave más grande entre los hijos izquierdo y derecho, entonces intercambie), y haga el subárbol un montón. Luego, filtre el subárbol enraizado en cada nodo (Ln/2J-1~1) para ver si el valor del nodo es mayor que el valor de sus nodos secundarios izquierdo y derecho. De lo contrario, los nodos secundarios izquierdo y derecho El valor más grande en el nodo se intercambia con él, y el almacenamiento dinámico del siguiente nivel puede destruirse después del intercambio, así que continúe utilizando el método anterior para construir el almacenamiento dinámico del siguiente nivel hasta que el subárbol enraizado en el nodo forme un almacenamiento dinámico. Utilice repetidamente el método anterior para ajustar el montón para construir el montón hasta el nodo raíz.

2. Ejemplo de ajuste

Ajuste inicialmente el subárbol L(4), 09 < 32, intercambie y cumpla con la definición del montón después del intercambio; continúe ajustando el subárbol L(3) hacia delante, 78<el mayor de los hijos izquierdo y derecho, 87, intercambio, y satisfacer el montón después del intercambio Definición; ajustar el subárbol L(2) hacia adelante, 17 < el mayor de los hijos izquierdo y derecho 45, y cumplir con la definición del montón después del intercambio; ajustar hacia adelante al nodo raíz L (1), 53 < el mayor de los hijos izquierdo y derecho 87. Intercambio. Después del intercambio, se destruye el montón del subárbol L(3). Use el método anterior para ajustar L(3). 53<el mayor de los hijos izquierdo y derecho 78. Intercambio, hasta ahora el árbol binario completo cumple con la definición del montón.

inserte la descripción de la imagen aquí

3. Implementación del lenguaje C

void Heapsort(SqList &L){
    
    
	buildMaxheap(L);
	for(int i=L.length-1;i>0;i--){
    
    
		Elemtype temp=L.data[i];
		L.data[i]=L.data[0];
		L.data[0]=temp;
		HeadAdjust(L,0, i);
	}
}

4. Análisis de eficiencia

El análisis de rendimiento del algoritmo de clasificación de almacenamiento dinámico es el siguiente:

  • Eficiencia espacial: Solo se utiliza un número constante de unidades auxiliares, por lo que la complejidad espacial es 0(1).
  • Eficiencia de tiempo: el tiempo para construir un montón es O(n), y luego hay n-1 operaciones de ajuste a la baja, y la complejidad de tiempo de cada ajuste es O(h), así que en el mejor, peor y promedio de los casos, el montón sorting La complejidad del tiempo es O(nlog2n).
  • Estabilidad: al filtrar, es posible ajustar los siguientes elementos con la misma palabra clave al frente, por lo que el algoritmo de clasificación del montón es un método de clasificación inestable. Por ejemplo, en la tabla L= {1, 2 , 2}, al construir el montón inicial, 2 se puede intercambiar en la parte superior del montón, en este momento L= { 2 , 1,2}, y la secuencia de clasificación final es L={1,2, 2 } , obviamente, el orden relativo de 2 y 2 ha cambiado.

4. Un ejemplo completo de implementación en lenguaje C

/*我们今天的主角插入排序是基于查找算法来的,所以我们还是利用线性表来进行模拟*/

/*为了便于我们后面演示希尔排序,所以我们采用顺序存储结构*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MaxSize 50                //这里只是演示,我们假设这里最多存五十个学生信息

//定义学生结构
typedef struct {
    
    
	char name[200];              //姓名
	int  grade;               //分数,这个是排序关键字
} Elemtype;

//声明使用顺序表
typedef struct {
    
    
	/*这里给数据分配内存,可以有静态和动态两种方式,这里采用动态分配*/
	Elemtype  *data;            //存放线性表中的元素是Elemtype所指代的学生结构体
	int length;                 //存放线性表的长度
} SqList;						//给这个顺序表起个名字,接下来给这个结构体定义方法

//初始化线性表
void InitList(SqList &L){
    
    
	/*动态分配内存的初始化*/
	L.data = (Elemtype*)malloc(MaxSize * sizeof(Elemtype));  //为顺序表分配空间
	L.length = 0;                                            //初始化长度为0
}

//求表长函数
int Length(SqList &L){
    
    
	return L.length;
}

//求某个数据元素值
bool GetElem(SqList &L, int i, Elemtype &e) {
    
    
	if (i < 1 || i > L.length)
		return false;         //参数i错误时,返回false
	e = L.data[i - 1];      //取元素值
	return true;
}

//输出线性表
void DispList(SqList &L) {
    
    
	if (L.length == 0)
		printf("线性表为空");
	//扫描顺序表,输出各元素
	for (int i = 0; i < L.length; i++) {
    
    
		printf("%s        %d", L.data[i].name,  L.data[i].grade);
		printf("\n");
	}
	printf("\n");
}

//插入数据元素
bool ListInsert(SqList &L, int i, Elemtype e) {
    
    
	/*在顺序表L的第i个位置上插入新元素e*/
	int j;
	//参数i不正确时,返回false
	if (i < 1 || i > L.length + 1 || L.length == MaxSize)
		return false;
	i--;                //将顺序表逻辑序号转化为物理序号
	//参数i正确时,将data[i]及后面的元素后移一个位置
	for (j = L.length; j > i; j--) {
    
    
		L.data[j] = L.data[j - 1];
	}
	L.data[i] = e;      //插入元素e
	L.length++;         //顺序表长度加1
	return true;
	/*平均时间复杂度为O(n)*/
}

//简单选择排序
void selectsort(SqList &L){
    
    
	for(int i=0;i<L.length-1;i++){
    
          //一共进行n-1趟
		Elemtype min=L.data[i];        //记录最小的元素位置
		int n=0;
		for(int j=i+1;j<L.length;j++){
    
      //从未排序部分开始遍历
			if(L.data[j].grade<min.grade) {
    
    
				min=L.data[j];
				n=j;
			}
		}
		if(min.grade!=L.data[i].grade){
    
    
			Elemtype temp=L.data[i];
			L.data[i]=L.data[n];
			L.data[n]=temp;
		}
	}
}

void HeadAdjust(SqList &L,int k, int len){
    
    
	Elemtype temp=L.data[k];
	for(int i=2*k+1;i<len;i=2*i+1){
    
    
		if(i<len-1 && L.data[i].grade<L.data[i+1].grade)
			i++;
		if(temp.grade>=L.data[i].grade)
			break;
		else{
    
    
			L.data[k]=L.data[i];
			k=i;
		}
	}
	L.data[k]=temp;
}

void buildMaxheap(SqList &L){
    
    
	for(int i=L.length/2-1;i>=0;i--)
		HeadAdjust(L, i, L.length);
}

void Heapsort(SqList &L){
    
    
	buildMaxheap(L);
	for(int i=L.length-1;i>0;i--){
    
    
		Elemtype temp=L.data[i];
		L.data[i]=L.data[0];
		L.data[0]=temp;
		HeadAdjust(L,0, i);
	}
}

int main(){
    
    
	SqList L;
	Elemtype stuents[10]={
    
    {
    
    "张三",649},{
    
    "李四",638},{
    
    "王五",665},{
    
    "赵六",697},{
    
    "冯七",676},
		{
    
    "读者",713},{
    
    "阿强",627},{
    
    "杨曦",649},{
    
    "老六",655},{
    
    "阿黄",604}};
	//这一部分忘了的请回顾我的相关博客
	printf("初始化顺序表并插入开始元素:\n");
	InitList(L);         //这时是一个空表,接下来通过插入元素函数完成初始化
	for (int i = 0; i < 10; i++)
		ListInsert(L, i + 1, stuents[i]);
	DispList(L);
	/*printf("根据分数进行简单选择排序后结果为:\n");
	selectsort(L);
	DispList(L);          //到这一步我们的简单选择排序没什么问题的
	 */
	printf("根据分数进行堆排序后结果为:\n");
	Heapsort(L);
	DispList(L);
}

5. Ejecución de resultados

1. Clasificación de selección simple

inserte la descripción de la imagen aquí

2. Clasificación en montón

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_51496226/article/details/131673994
Recomendado
Clasificación