10. Търсене. Последователно и двоично търсене. Търсене с връщане
План:
Задачи 9 и 10
Последователно търсене
Двоично търсене (разделай и владей)
Класификация на задачите
Tърсене с връщане
-- Разходка на коня
-- Задача за осемте царици
Задачи 11 и 12
Последователно търсене [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] (Binary
search algorithm)
// 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);
}
Търсене на корен на уравнение с произволна точност
Класификация на задачите [6.1]
Сложност по време [6.1.1]
NP- задачи: Класът на полиномиално проверимите задачи
P- задачи: Съществува решение с полиномиална сложност
P = NP ??? (P versus
NP problem)
Експоненциални задачи: Съществува алгоритъм с експоненциална
сложност
Сложност по памет [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;
}
Неопределени задачи:
-- Задача на Сколем (Skolem problem)
-- За дадена матрица дали съществува число n такова, че матрицата, повдигната на степен n
съдържа нула в горния десен ъгъл.
NP-пълни
задачи [6.2]
Търсене с връщане [6.3]
Разходка на коня [6.3.4] (Knight's tour)
// 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] (Eight
queens puzzle)
// 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]
Задача за търговския пътник (Travelling
salesman problem)
Задача за раницата (Knapsack
problem)