Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.10.2010, 08:49   #1
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию Случайное число

Имеются два массива чисел - два "чёрных списка" (ч.с). Нужно сгенерировать число (0<=X<=49), отличное от элементов ч.с. Делаю так: генерирую число и сравниваю с элементами ч.с, пока не получится подходящее число. Хотя этот конкретный пример работает довольно быстро но код неэффективен при большом размере ч.с. Возникают т.н. неопределённые отсрочки. Подскажите хотя бы, в каком направлении мне думать? Спасибо.

Вот код. Написан наверное коряво, только учусь...
Код:
#include <iostream.h>

void getNumber()
{
	const int aSize = 7;
	const int bSize = 8;
	const int limit = 50;
	int a[aSize]={1,5,8,15,23,44,49}; // Ч.с 1
	int b[bSize]={3,7,9,16,30,32,40,42}; // Ч.с. 2

	int x,i;
	bool f=true;	// Признак совпадения с ч.с.

	while(f==true)	// Выполнять, пока X попадает в ч.с
	{
		f=false;
		x=rand()%limit;	// Генерация X
		for(i=0; i<aSize; i++) // Сравнение с ч.с. 1
			if(x==a[i])
			{
				f=true;
				break;
			}

		if (!f)
			for(i=0; i<bSize; i++) // Сравнение с ч.с. 2
				if(x==b[i])
				{
					f=true;
					break;
				}
	}
	cout<<"X = "<<x<<endl;
}

int main()
{
	int j;
	srand(time(NULL));
	clock_t t0 = clock();
	for(j = 0; j<100000; j++)	// Прогон функции 10000 раз
		getNumber();
	clock_t t1 = clock();
	cout << "\ntime: " << (double)(t1 - t0) / CLOCKS_PER_SEC << endl;


	cout<<endl;
	system("pause");
	return 0;
}

Последний раз редактировалось rommster; 07.10.2010 в 13:33. Причина: Забыл выложить код:
rommster вне форума Ответить с цитированием
Старый 07.10.2010, 09:23   #2
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

ну, как я понимаю, других вариантов и быть не может!
Единственное, в Ч.С. нужно ввести сортировку и проверять очередное случайное число на наличие в Ч.С. по ключу (чтобы избавиться от перебора).


ДОБАВЛЕНО

Цитата:
0<=X<=49
речь идёт о целых числах, как я понимаю?!
Дык, тогда чисел в чёрном списке может быть не больше 50 ?!! Тогда, как не крути - будет всё равно быстро )

А по поводу того, что других вариантов и быть не может - я не прав!
Тут, как раз, раз множесто чисел такое маленькое - вариантов пруд пруди.
Например, заполняем матрицу числами от 0 до 49
потом удаляем из неё те числа, которые есть в обоих Ч.С. - как удалить число из массива - думаю, вопросов не вызывает?
Потом берём любое число из этого массива (получаем случайный индекс).
Всё.
плюс такого подхода ещё в том, что если вдруг Ч.С. полностью закрывают диапазон от 0 до 49 - то это сразу можно будет увидеть - в исходном массиве не останется ни одного числа!
А в случае с перебором цикл будет крутиться до бесконечности!

Последний раз редактировалось Serge_Bliznykov; 07.10.2010 в 09:29.
Serge_Bliznykov вне форума Ответить с цитированием
Старый 07.10.2010, 13:49   #3
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию

Serge_Bliznykov, спасибо за советы. Ну 50 это у меня так, к примеру, на самом деле может быть до 10000) Попробовал сделать, как вы советовали, не знаю насколько правильно, но работает.
Код:
#include <iostream.h>

void getNumber()
{
	const int aSize = 7;
	const int bSize = 8;
	const int limit = 50;
	int a[aSize]={1,5,8,15,23,44,49}; // Ч.с 1
	int b[bSize]={3,7,9,16,30,32,40,42}; // Ч.с. 2

	int x,i,j,k;
	int tmp[limit], tmpN;
	int size = limit;
	for(i=0; i<size; i++)
		tmp[i] = i;

	for(i=0; i<aSize; i++)  // отмечаю -1 те эл-ты, которые надо удалить,
		tmp[a[i]]=-1;    // ибо как удалить сразу и при этом быстро - не могу придумать


	for(i=0; i<bSize; i++)
		tmp[b[i]]=-1;


	for(i=0; i<size; i++) // удаляю сдвигом, не уверен, что правильно
	{
		if(tmp[i]==-1)
		{
			for(j=i; j<size-1; j++)
			{
				tmp[j]=tmp[j+1];
			}
			i--;
			size--;
		}
	}
	x = tmp[rand()%size];
	cout<<"X = "<<x<<endl;;

}

int main()
{
	int j;
	srand(time(NULL));
	clock_t t0 = clock();

	for(j = 0; j<100000; j++)
		getNumber();

   	clock_t t1 = clock();
	cout << "\ntime: " << (double)(t1 - t0) / CLOCKS_PER_SEC << endl;
	cout<<endl;
	system("pause");
	return 0;
}
Проблема только в том, что этот код работает ещё медленнее. Так время 100000 прогонов первой проги = 0.032c, второй 0.927 (без учёта печати на экран). Если же увеличить limit 1000, а размер ч.с. до 500, то первая выполняется за 7.031с, а вторая - 104.141(!!!). Первый вариант работает таки быстрее, но при рандомной генерации числа ведь можно попадать несколько раз в одну и ту же точку? Означает ли это вероятность бесконечно долгого выполнения?

Последний раз редактировалось rommster; 07.10.2010 в 13:52.
rommster вне форума Ответить с цитированием
Старый 07.10.2010, 14:00   #4
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
rommster
Почему не сортируешь массивы черных списков?
Если отсортируешь появится возможность бинарного поиска - а это самое быстрое из того что тебе нужно. Все равно у тебя числа, вот и отсортируй по возрастанию массивы а и б, и потом при получении случайного числа бинарным поиском по массиву получай ответ есть ли такое или нет.
Как бинарный поиск вести знаешь?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 07.10.2010, 14:41   #5
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию

Попробовал с бинарным поиском, если правильно конечно написал. Массивы по умолчанию уже отсортированы.
Код:
bool binarySearch(int a[], int size, int key)
{
	int middle, high, low;
	low=0;
	high=size-1;
	while (low <= high)
	{
		middle = (low + high) / 2;
		if (a[middle] == key)
			return true;
		if (a[middle] < key)
			low = middle + 1;
		if (a[middle] > key)
			high = middle - 1;
	}
	return false;
}


void getNumber()
{
	const int aSize = 7;
	const int bSize = 8;
	const int limit = 50;
	int a[aSize]={1,5,8,15,23,44,49};
	int b[bSize]={3,7,9,16,30,32,40,42};
	int x,i,step=0;
	bool f=true;

	while(f==true)
	{
		step++;
		f=false;
		x=rand()%limit;	// Генерация X
			if(binarySearch (a, aSize, x))
			{
				f=true; continue;
			}

			if(binarySearch (b, bSize, x))
				f=true;
	}
	cout<<"\t\tX = "<<x<<"\tStep = "<<step<<endl;
}
Даёт ощутимую прибавку для больших размеров, для малых почти то же самое. Но суть не в этом, я вот что хотел узнать: при получении случайного числа нужно проверять есть оно в ч.с. или нет. Может ли случиться так, что будут постоянно генерироваться числа которые есть в ч.с. и задержка будет очень долгой?
rommster вне форума Ответить с цитированием
Старый 07.10.2010, 14:50   #6
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Может ли случиться так, что будут постоянно генерироваться числа которые есть в ч.с. и задержка будет очень долгой?
В принципе да. Но с такой же вероятностью как и сорвать джек-пот у однорукого бандита.
Если будешь генерировать случайное число в пределах, то на такое врядли попадешся. Более того я бы даже посоветовал сдвигать пределы. Запоминать места где есть дырки и генерировать не со всей последовательности а только по тем частям массива где заведомо извесны дырки, тогда вообще ничего не придется искать.
Сейчас я попробую оформить мыслю в виде кода...

ДОПИСАНО:
Вот что я имел ввиду:
Код:
// sfsdf.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"
#include <iostream>
#include <locale>
#include <math.h>
#include <list>
#include <conio.h>
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
    setlocale(LC_ALL,"russian");
    list<int> l1;
    int b;
    b=1;    l1.push_back(b);
    b=5;    l1.push_back(b);
    b=34;    l1.push_back(b);
    b=100;    l1.push_back(b);
    b=120;    l1.push_back(b);

    do{
    for(list<int>::iterator i=l1.begin();i!=l1.end();i++){
        int bb, l=*i,h=*++i;
        
        if (l<h){
            bb=(double)rand() / (RAND_MAX + 1) * (h - l)+ l;
            
            
            if(bb!=l&&bb!=h){ 
                l1.insert(i,bb);
                cout<<" new="<<bb<<'\t';
                break;
            }
        }
    }
    for(list<int>::iterator i=l1.begin();i!=l1.end();i++){
        int bb, l=*i;
        cout<<l<<'\t';
    }
    cout<<'\n';
    }while(getch()!=13);
    system("pause");
    return 0;
}
I'm learning to live...

Последний раз редактировалось Stilet; 07.10.2010 в 15:35.
Stilet вне форума Ответить с цитированием
Старый 07.10.2010, 15:41   #7
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
Запоминать места где есть дырки и генерировать не со всей последовательности а только по тем частям массива где заведомо извесны дырки
Ага, тоже об этом думал) Но ничего путного так и не получилось) Спасибо, пойду разбираться!
rommster вне форума Ответить с цитированием
Старый 08.10.2010, 09:09   #8
coinkrsk
пыжашийся нуб
Пользователь
 
Регистрация: 19.06.2010
Сообщений: 93
По умолчанию

Если тебе нужно многократно и быстро генерировать уникальные случайные числа из некого диапазона, то я бы на твоем месте сначала один раз прошелся по всем черным спискам и создал массив уникальных элементов. Потом уже без всяких проверок можешь генерировать свои числа подставляя случайное число, как индекс полученного массива.
coinkrsk вне форума Ответить с цитированием
Старый 08.10.2010, 10:08   #9
coinkrsk
пыжашийся нуб
Пользователь
 
Регистрация: 19.06.2010
Сообщений: 93
По умолчанию

Бывает же такое. Заинтерисовал своей задачкой. Я даже сел и написал.
Код:
#include <iostream>
#include <vector>
#include <time.h>
using std::cout;
using std::endl;

class UnicNumGenerator
{
public:
	UnicNumGenerator(	const int* pBlackList_1, int blackListSize_1, 
						const int* pBlackList_2, int blackListSize_2,
						int limit);
	int generate();
private:
	bool binarySearch(const int* a, int length, int key);
	std::vector<int> unicNumList;
	//int unicNumListSize;

};

bool UnicNumGenerator::binarySearch(const int* a, int length, int key) 
{
	int low = 0;
	int high = length - 1;

	while (low <= high) 
	{
		int mid = low + ((high - low) / 2);
		int midVal = a[mid];

		if (midVal < key)
			low = mid + 1;
		else if (midVal > key)
			high = mid - 1;
		else
			return true; // key found
	}
	return false;  // key not found.
}

UnicNumGenerator::UnicNumGenerator(	const int* pBlackList_1, int blackListSize_1, 
									const int* pBlackList_2, int blackListSize_2,
									int limit)
{
	for(int i = 0; i < limit; i++)
		if (!binarySearch( pBlackList_1, blackListSize_1, i ) &&
			!binarySearch( pBlackList_2, blackListSize_2, i ) )
				unicNumList.push_back(i);
}

int UnicNumGenerator::generate()
{
	return unicNumList[ rand() % unicNumList.size() ];
}


int main()
{
	std::srand( (unsigned)time(0) );

	const int aSize = 7;
	const int bSize = 8;
	const int limit = 50;
	int a[aSize]={1,5,8,15,23,44,49}; // Ч.с 1
	int b[bSize]={3,7,9,16,30,32,40,42}; // Ч.с. 2


	clock_t begin, end;

	begin = clock();

	UnicNumGenerator myGenerator( a, aSize, b, bSize, limit );

	for(int j = 0; j < 100000; j++)
		myGenerator.generate();
		//cout << myGenerator.generate() << ' ';

	end = clock();
	cout << "\ntime: " << (double)(end - begin) / CLOCKS_PER_SEC << endl;
	
	return 0;
}
на моем тормозном ноутбуке:
при limit=50 время 0.004 секунды
при больших лимитах выйгрыш вообще будет несравнимым.

Последний раз редактировалось coinkrsk; 08.10.2010 в 10:20.
coinkrsk вне форума Ответить с цитированием
Старый 08.10.2010, 13:48   #10
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию

coinkrsk, спасибо, шустро летает! Я в своём посте #3 выкладывал свой код с такой же по сути идеей - составлять массив уникальных элементов. Только работает он слишком тормозно. Я конечно понимаю, что код жуткий: использую простой поиск вместо бинарного, тупое удаление элемента массива и.т.п. Но неужто только из-за этого прога может выполняться аж 100 секунд вместо долей секунды, как у вас? Дело в использовании вектора что ли?
rommster вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Случайное число. Alex Cones Свободное общение 27 06.06.2010 09:54
Программа, загадывающая случайное число fs444 Общие вопросы C/C++ 2 24.03.2010 20:19
случайное число Дініс Общие вопросы C/C++ 3 07.10.2009 23:03
Случайное число Altera Общие вопросы Delphi 4 05.02.2008 22:22
Как згенерировать случайное число SeRhy Помощь студентам 2 25.11.2007 20:27