8. Търсене
Последователно търсене [4, стр. 231]
** Човешката дейност търсене
** Опростен модел на търсене
** Фундаментални операции над елемнтите на множество (правилна
оценка на ефективността на алгоритмите за търсене)
-- инициализиране
-- търсене
-- вмъкване
-- изтриване
-- обединяване на множества
-- сортиране.
** Ключ, повтарящи се ключове
-- има ли елемент с даден ключ? [bool exists(unsigned key)]
-- индекс на елемент (обект) с даден ключ? [unsigned find_one(unsigned
key)]
-- брой елементи с даден ключ? [unsigned count(unsigned key)]
-- индекси на всички елементи (обекти) с даден ключ? [vector<unsigned>
find_all(unsigned key)]
** Последователно (линейно) търсене
Проверяваме последователно елементите на множеството (което е
линейно наредено), докато или намерим търсения елемент или стигнем
до края на редицата.
Ефективност на алгоритъма за линейно търсене:
Броят на обръщенията към елементите на масива зависи от търсеното
число, но в най-лошия случай, когато числото не се среща в масива,
е равен на дължината на масива. Следователно сложността на
алгоритъма е O(n).
// lsearch.cpp
int
linear_search(vector<int> v, int a)
{
int i;
for (i = 0; i <
v.size(); i++)
if (v[i] == a) return i;
return -1;
}
** Последователно търсене в сортиран списък с поддържане на
сортирания списък при вмъкване на нов елемент.
** Последователно търсене с преподреждане
Двоично търсене (разделай и владей) [4.3, стр. 239]
// bsearch.cpp
int
binary_search(vector<int> v, int from, int to, int
a)
{
if (from >
to) return -1;
int mid = (from + to)
/ 2;
int diff = v[mid] - a;
if (diff == 0) return
mid;
/* v[mid] == a */
else if (diff <
0)
/* v[mid] < a */
return binary_search(v, mid + 1, to, a);
else
return binary_search(v, from, mid - 1, a);
}
Търсене и сортиране на реални данни
// esearch.cpp
int
binary_search(vector<Employee> v, int from, int to,
string n)
{
if (from > to)
return -1;
int mid = (from + to)
/ 2;
if (v[mid].get_name()
== n) return mid;
else if
(v[mid].get_name() < n)
return binary_search(v, mid + 1, to, n);
else
return binary_search(v, from, mid - 1, n);
}
Tърсене с връщане
Класификация на задачите [6.1]
Сложност по време [6.1.1]
NP- задачи: Класът на полиномиално проверимите задачи
P- задачи: Съществува решение с полиномиална сложност
Експоненциални задачи: Съществува алгоритъм с експоненциална
сложност
Сложност по памет [6.1.2]
Нерешими задачи [6.1.3]
Задачи, за които съществува доказателство, че не могат да бъдат
решени, независимо от това с колко време и памет разполагаме.
Примери [6.1.4]
Полиномиално решими задачи: търсене, сортиране, ...
NP- задачи: Съществуване на делител на цяло положително число,
по-малък от зададено число.
Класификация по памет: игра на шах
Нерешими задачи: Дали дадена програма е в безкраен цикъл.
int main()
{
unsigned a,
b , c, n, u;
for (u =
3;;)
{
for (a = 1; a < u; a++)
for (b = 1; b < u; b++)
for (c=1;
c < u; c++)
for (n=3; n < u; n++)
if (pow(a, n) + pow(b, n) ==
pow(c, n)) exit(0);
u++;
}
return 0;
}
Неопределени задачи: Задача на Сколем - За дадена матрица дали
съществува число n такова,
че матрицата, повдигната на степен n съдържа нула в горния десен
ъгъл.
NP-пълни задачи [6.2]
(Wiki)
Търсене с връщане [6.3]
Разходка на коня [6.3.4]
// knight.c
#include <stdio.h>
#include <stdlib.h>
#define MAXN 10
#define MAXD 10
const unsigned n = 6;
const unsigned startX = 1;
const unsigned startY = 1;
const unsigned maxDiff = 8;
const int diffX[MAXD] = { 1,
1, -1, -1, 2, -2, 2, -2 };
const int diffY[MAXD] = { 2,
-2, 2, -2, 1, 1, -1, -1 };
unsigned board[MAXN][MAXN];
unsigned newX, newY;
void printBoard(void)
{ unsigned i, j;
for (i = n; i > 0;
i--) {
for (j = 0;
j < n; j++) printf("%3u", board[i-1][j]);
printf("\n");
}
exit(0);
}
void nextMove(unsigned X,
unsigned Y, unsigned i)
{ unsigned k;
board[X][Y] = i;
if (i == n * n) {
printBoard(); return; }
for (k = 0; k <
maxDiff; k++) {
newX = X +
diffX[k]; newY = Y + diffY[k];
if ((newX
>= 0 && newX < n && newY >= 0 &&
newY < n) && (0 == board[newX][newY]))
nextMove(newX, newY, i + 1);
}
board[X][Y] = 0;
}
int main(void) {
unsigned i, j;
for (i = 0; i < n;
i++)
for (j = 0;
j < n; j++) board[i][j] = 0;
nextMove(startX-1,
startY-1, 1);
printf("No solution.
\n");
return 0;
}
Задача за осемте царици
[6.3.5]
// queens.c
#include<stdio.h>
#include<stdlib.h>
#define MAXN 100
const unsigned n = 13;
unsigned col[MAXN] , RD[2*MAXN
- 1],
LD[2*MAXN], queens [MAXN];
void printBoard()
{ unsigned i , j ;
for (i = 0; i < n;
i++) {
printf("\n");
for (j = 0;
j < n; j++)
if(queens[i] == j) printf("x ");
else printf(". ");
}
printf("\n");
exit(0);
}
void generate(unsigned i)
{ if(i == n) printBoard();
unsigned
k;
for (k = 0; k <= n;
k++) {
if (col[k]
&& RD[i + k] && LD[n + i - k]) {
col[k] = 0; RD[i + k] = 0; LD[n + i - k] = 0; queens[i] = k;
generate(i + 1);
col[k] = 1; RD[i + k] = 1; LD[n + i - k] = 1;
}
}
}
int main(void) {
unsigned i;
for (i = 0; i < n;
i++) col[i] = 1;
for (i = 0; i < (2*n
- 1); i++) RD[i] = 1;
for (i = 0; i < 2*n;
i++) LD[i] = 1;
generate(0);
printf("No
solution!\n");
return 0;
}
Метод на разклоненията и границите
[6.4]
http://optlab-server.sce.carleton.ca/POAnimations2007/BranchAndBound.html
Задача за раницата