1.
Pesquisa binária Pesquisa binária, também conhecida como pesquisa binária, a premissa da pesquisa binária é que a tabela ou árvore linear foi classificada. Aqui, a tabela linear é tomada como exemplo. Supõe-se que a tabela linear foi classificada por palavras-chave e está aumentando Organizado ordenadamente.
A ideia da pesquisa binária: deixe a tabela linear R [esquerda, direita] ser o intervalo de pesquisa atual, primeiro determine a posição do ponto médio do intervalo mid = (esquerda + direita) / 2 e, em seguida, compare o valor K a ser verificado com R [mid] A comparação de .key é a seguinte:
1) Se K = R [mid] .key, então retorne diretamente o índice do elemento;
2) Se K <R [mid] .key, então
left = mid-1;
mid = (esquerda + direita) / 2;
pesquisa no intervalo da metade esquerda [esquerda, meio-1];
3) Se K> R [meio] .tecla, então
direita = meio + 1;
meio = (esquerda + direita) / 2;
Pesquise na metade direita do intervalo [esquerda, meio-1];
4) Repita as etapas 2) e 3) até esquerda> direita, ou seja, o espaço de pesquisa passa a 0. Se encontrado, retorna o índice do elemento. Caso contrário, retorna -1.
Pesquisa binária, a cada pesquisa, o intervalo de pesquisa é reduzido pela metade, então o algoritmo é muito rápido, a complexidade do tempo é O (log n) O (log \, n)O ( l o gn ) .
// Pesquisa binária binarySearch ()
int binarySearch(int arr[], int n, int target) {
int left = 0, right = n-1;
while (left <= right) {
int mid = (left+right)/2;
if(arr[mid] == target)
return mid;
if(arr[mid] > target)
right = mid - 1;
else
left = mid + 1;
}
return -1;
}
2. Classificação por
seleção O método básico de classificação por seleção é: cada etapa seleciona o registro com a menor palavra-chave dos registros a serem classificados e a ordem é colocada no final dos registros classificados até que todas as classificações sejam concluídas. A classificação de seleção inclui classificação de seleção direta e classificação de heap. Aqui está uma classificação de seleção direta.
O processo de seleção direta e classificação é: suponha que os registros são colocados em R [0, n-1], R [0, i-1] é a área ordenada, R [i, n-1] é a área desordenada, e há Todas as palavras-chave na área de sequência são menores do que todas as palavras-chave na área de desordem. É necessário adicionar R [i] a R [0, i-1] para fazer R [0, i] ordenado. Aqui, cada passagem seleciona um registro R [k] com a menor chave da área desordenada R [i, n-1] e o troca por R [i]. Obviamente, R [0, i] torna-se Uma nova área ordenada.
2.1) Use a estrutura para indicar a classificação de seleção direta
#define MaxSize 100
typedef int KeyType;
typedef char ElemType;
typedef struct{
KeyType key; //关键字域
ElemType data[10]; //其他数据域
}SqList;
void SelectSort(SqList R[], int n) {
int i, j, k;
SqList tmp;
for (i = 0; i < n - 1; j++) {
k = i;
for (j = i + 1; j < n; j++) {
if (R[j].key < R[k].key)
k = j;
}
tmp = R[i];
R[i] = R[k];
R[k] = tmp;
}
}
2.2 Use uma matriz para indicar a classificação de seleção direta
//交换a和b 方法一
void swapValue(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
//交换a和b 方法二
void swapValue2(int &a, int &b) {
a = a + b;
b = a - b;
a = a - b;
}
//直接选择排序
void selectionSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
swapValue(arr[i], arr[minIndex]);
}
}
3. Escrevendo casos de teste para algoritmos
3.1 Coloque todos os algoritmos em um espaço de comando, como o namespace MyAlgorithmTester, que é um arquivo de cabeçalho: MyAlgorithm.h
//MyAlgorithm.h
#ifndef MY_ALGORITHM_H
#define MY_ALGORITHM_H
#include <iostream>
#include <cassert>
#include <cmath>
using namespace std;
#define min(a,b) (((a)<(b))?(a):(b))
namespace MyAlgorithmTester {
//O(logN)
int binarySearch(int arr[], int n, int target) {
int left = 0, right = n-1;
while (left <= right) {
int mid = (left+right)/2;
if(arr[mid] == target)
return mid;
if(arr[mid] > target)
right = mid - 1;
else
left = mid + 1;
}
return -1;
}
//O(N)
int findMax(int arr[],int n) {
assert(n > 0);
int res = arr[0];
for (int i=1;i<n;i++) {
if(arr[i] > res)
res = arr[i];
}
return res;
}
//O(NlogN)
void __merge(int arr[],int left,int mid,int right, int aux[]) {
int i = left,j = mid+1;
for(int k=left; k<= right; k++) {
if (i > mid) {
arr[k] = aux[j];
j++;
}
else if (j > right) {
arr[k] = aux[i];
i++;
}
else if (aux[i] < aux[j]) {
arr[k] = aux[i];
i++;
}
else {
arr[k] =aux[j];
j++;
}
}
}
//自顶向上排序
void mergeSort(int arr[], int n) {
int *aux = new int[n];
for (int i=0;i<n;i++) {
aux[i] = arr[i];
}
for (int sz=1;sz<n;sz += sz) {
for (int i=0; i < n; i += sz+sz) {
__merge(arr,i,i+sz-1,min(i+sz+sz-1, n-1), aux);
}
}
delete[] aux;
return;
}
//O(N^2)
void selectionSort(int arr[], int n) {
for (int i=0;i<n-1; i++) {
int minIndex = i;
for (int j=i+1; j<n; j++) {
if(arr[j] < arr[minIndex])
minIndex = j;
}
swap(arr[i],arr[minIndex]);
}
}
}
#endif
3.2) Coloque a função que gera o conjunto de dados no namespace MyUtil, que também é um arquivo de cabeçalho: MyUtil.h
//MyUtil.h
#ifndef MY_UTIL_H
#define MY_UTIL_H
#include <iostream>
#include <cassert>
#include <ctime>
using namespace std;
namespace MyUtil {
int *generateRandomArray(int n, int rangeL, int rangeR) {
assert(n > 0 && rangeL <= rangeR );
int *arr = new int[n];
srand(time(NULL));
for (int i = 0; i < n; i++) {
arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
}
return arr;
}
int *generateOrderedArray(int n) {
assert(n > 0);
int *arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i;
}
return arr;
}
}
#endif
3.3) Escreva a função principal
//main.cpp
#include "MyAlgorithm.h"
#include "MyUtil.h"
#include <cmath>
#include <ctime>
#include <windows.h>
using namespace std;
int main() {
//1) findMax 数据规模倍乘测试
//O(n)
//for (int i = 10; i <= 26; i++) {
// int n = pow(2, i);
// int *arr = MyUtil::generateRandomArray(n, 0, 100000000);
// clock_t startTime = clock();
// MyAlgorithmTester::findMax(arr, n);
// clock_t endTime = clock();
// cout << "data size 2^" << i << " = " << n << "\t";
// cout << "Time cost: " << double(endTime - startTime) / CLOCKS_PER_SEC << endl;
// delete[] arr;
//}
//2) selectionSort 数据规模倍乘测试
//O(n^2)
//cout << "Test for selectionSort:" << endl;
//for (int i = 10; i <= 15; i++) {
// int n = pow(2, i);
// int *arr = MyUtil::generateRandomArray(n, 0, 100000000);
// clock_t startTime = clock();
// MyAlgorithmTester::selectionSort(arr, n);
// clock_t endTime = clock();
// cout << "data size 2^" << i << " = " << n << "\t";
// cout << "Time cost: " << double(endTime - startTime) / CLOCKS_PER_SEC << endl;
// delete[] arr;
//}
//3) binarySearch 数据规模倍乘测试
//O(logn)
//cout << "Test for selectionSort:" << endl;
//double run_time = 0;
//LARGE_INTEGER time_start;
//LARGE_INTEGER time_end;
//double dqFreq;
//LARGE_INTEGER freq;
//QueryPerformanceFrequency(&freq);
//dqFreq = (double)freq.QuadPart;
//for (int i = 10; i <= 27; i++) {
// int n = pow(2, i);
// int *arr = MyUtil::generateRandomArray(n, 0, 100000000);
// QueryPerformanceCounter(&time_start);
// MyAlgorithmTester::binarySearch(arr, n, 0);
// QueryPerformanceCounter(&time_end);
// run_time = 1000000 * (time_end.QuadPart - time_start.QuadPart) / dqFreq;
// cout << "data size 2^" << i << " = " << n << "\t";
// cout << "Time cost: " << run_time << endl;
// delete[] arr;
//}
//4) binarySearch 数据规模倍乘测试
//O(logn)
cout << "Test for selectionSort:" << endl;
double run_time = 0;
LARGE_INTEGER time_start;
LARGE_INTEGER time_end;
double dqFreq;
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
dqFreq = (double)freq.QuadPart;
for (int i = 10; i <= 26; i++) {
int n = pow(2, i);
int *arr = MyUtil::generateRandomArray(n, 0, 100000000);
QueryPerformanceCounter(&time_start);
MyAlgorithmTester::mergeSort(arr, n);
QueryPerformanceCounter(&time_end);
run_time = 1000 * (time_end.QuadPart - time_start.QuadPart) / dqFreq;
cout << "data size 2^" << i << " = " << n << "\t";
cout << "Time cost: " << run_time << endl;
delete[] arr;
}
system("pause");
return 0;
}
3.3) Descrição do algoritmo
a) findMax () Encontre o maior elemento no array.
Este algoritmo, quando a quantidade de dados dobra, o consumo de tempo do algoritmo dobra, indicando que a complexidade de tempo do algoritmo é linear, ou seja, a complexidade de tempo de findMax () é O (n) O (n)O ( n )。
b) selectionSort () seleciona e ordena diretamente
a matriz . Quando a quantidade de dados dobra, o algoritmo leva 4 vezes mais tempo, indicando que a complexidade de tempo do algoritmo é do tipo exponencial, com um expoente de log 2 4 = 2 log_2 {4} = 2l o g24=2 , ou seja, a complexidade de tempo do algoritmo selectionSort () éO (n 2) O (n ^ 2)O ( n2 )。
c) binarySearch () executa a pesquisa binária na matriz
. Quando a quantidade de dados dobra, o aumento demorado do algoritmo é muito pequeno, quase nenhum aumento. Pode-se inferir que a complexidade do tempo do algoritmo é O (log n) O (log \, n)O ( l o gn )。
c) mergeSort () funde e ordena
o array . Quando a quantidade de dados dobra, o algoritmo leva um pouco mais de 2 vezes, indicando que a complexidade do algoritmo está entre O (n) O (n)O ( n ) ~O (n 2) O (n ^ 2)O ( n2 ), pode-se especular que a complexidade de tempo do algoritmo éO (nlog n) O (nlog \, n)O ( n l o gn )。
Referências:
1. Exercícios de estrutura de dados e nível de análise B, Li Chunbao, 2006