Guest User

Untitled

a guest
Oct 20th, 2017
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.32 KB | None | 0 0
  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <cstdlib> //Для паузы.
  4. #include <fstream> //Для файла.
  5.  
  6. using namespace std; //Будем много пользоваться стандартными именами, поэтому подключаем всё их пространство.
  7.  
  8. int main() {
  9. setlocale(LC_ALL, "Russian"); //Подключили русский язык в консоли
  10. system("color 70"); //Белый фон, чёрный текст.
  11. system("title Apriori"); //Заголовок для консольного приложения.
  12.  
  13. ofstream fout("AprioriResult.txt"); //Связали с файлом, куда будем выводить.
  14. /*Используем сразу упорядоченную матрицу, где 0 - i-того товара нет, 1 - есть в чеке. Строки = транзакции.
  15. При необходимости можно реализовать через структуру отдельно таблицу, а сюда передавать ID продуктов.*/
  16. cout << "***APRIORI***" << endl << "Примечание: Для учебных задач обычно хватает трёх шагов." << endl << "Введите количество транзакций:" << endl;
  17. int TransCount; //Кол-во транзакций
  18. cin >> TransCount;
  19. cout << "Введите количество товаров:" << endl;
  20. int PrCount; //Кол-во товаров
  21. cin >> PrCount;
  22. fout << "Было " << TransCount << " транзакций с " << PrCount << " разными товарами." << endl; //Вывели в файл.
  23. int T[TransCount][PrCount]; //Матрица наличия
  24. cout << "Внесите данные о транзакциях, используя 0 для отсутствия товара, 1 для наличия." << endl;
  25. for (int i = 0; i < TransCount; i++){
  26. cout << "Введите позиции для чека №" << i + 1 << " :" << endl;
  27. fout << "Чек №" << i + 1 << ":" << endl;
  28. for (int j = 0; j < PrCount; j++){ cin >> T[i][j]; fout << T[i][j] << " "; }; //Заполяются "почеково".
  29. fout << endl;
  30. };
  31. int temp = 0; //Временная переменная
  32. cout << "Введите значение минимальной поддержки:" << endl;
  33. int minsup; //мин.поддержка.
  34. cin >> minsup; //Ввели значение минимальной поддержки.
  35. fout << "Минимальная поддержка равна " << minsup << "." << endl; //Выписываем в файл значение минимальной поддержки.
  36. cout << endl;
  37. /*Первый шаг.*/
  38. int C1[PrCount]; /*Кандидаты - все одноэлементные.*/
  39. for (int i = 0; i < PrCount; i++) { C1[i] = i + 1; }; //Заполнили одноэлеметными.
  40. int sup1[PrCount]; //Для каждого выделим место под поддержку.
  41. for (int i = 0; i < PrCount; i++){ sup1[i] = 0; }; //Очистили от мусора.
  42. for (int i = 0; i < PrCount; i++){ //Проверяем по товарам
  43. for (int j = 0; j < TransCount; j++){ //Для каждого товара каждую строку
  44. if (T[j][i] == 1) sup1[i]++; // если нашли 1, то поддержка увеличилась
  45. };
  46. };
  47. int num[PrCount]; //сохраним номера столбцов для будущего расчёта.
  48. for (int i = 0; i < PrCount; i++){ num[i] = 0; }; //Сохраним потом номера всех кандидатов.
  49. cout << "Поддержка на первом шаге у элементов:" << endl;
  50. fout << "Поддержка на первом шаге у элементов:" << endl;
  51. for (int i = 0; i < PrCount; i++){ cout << "{" << C1[i] << "} sup=" << sup1[i] << endl; fout << "{" << C1[i] << "} sup=" << sup1[i] << endl; }; //Выведем мн-ва с k=1 и их поддержку.
  52. for (int i = 0; i < PrCount; i++){ if (sup1[i] >= minsup) temp++; }; //Подсчитываем количество будущих часто встречающихся мн-в.
  53. int F1[temp]; //Выделяем память под часто встречающиеся мн-ва размерности k=1.
  54. cout << "Удовлетворяющих элементов: " << temp << endl;
  55. fout << "Удовлетворяющих элементов: " << temp << endl;
  56. if (temp == 0) {
  57. cout << "Больше часто встречающихся множеств не найдено." << endl;
  58. cout << "Результаты записаны в файл AprioriResult.txt." << endl;
  59. fout.close(); //Закрыли файл.
  60. system("pause");
  61. }; //Если таких нет, то выводим сообщение и останавливаем программу, закрываем текстовый файл.
  62. cout << "Эти элементы:" << endl;
  63. fout << "Эти элементы:" << endl;
  64. temp = 0; //Сбросим счётчик.
  65. for (int i = 0; i < PrCount; i++){
  66. if (sup1[i] >= minsup) { //Найдём эти часто встречающиеся множества.
  67. F1[temp] = C1[i]; //Если условие (поддержка больше или равна минимальной) выполнено, то заносим в память.
  68. num[temp] = i; // Сохраняем номер столбца из таблицы для данного элемента.
  69. cout << " {" << F1[temp] << "}, "; //Выводим на экран.
  70. fout << " {" << F1[temp] << "}, "; //Выводим в файл.
  71. temp++;
  72. } //Увеличиваем счётсчик для часто встречающихся множеств.
  73. };
  74. cout << endl;
  75.  
  76. /*Второй шаг.*/
  77. cout << "Перейдём ко второму шагу, кандидаты: ";
  78. fout << endl << "Кандидаты на втором шаге:";
  79. int temp2=temp*2;; // Мы будем использовать одномерный массив. Но нам нужны 2-элементные множества.
  80. //Значит, используем пары соседних ячеек.
  81. int C2[temp2]; //Выделим память для описанного выше массива кандидатов.
  82. int sup2[temp]; // Для пар нам понадобится подсчитать поддержку. Для пар, а не элементов пар!
  83. for (int i = 0; i < 100; i++){ sup2[i] = 0; };
  84. temp2 = 0; // Временные переменные.
  85. int temp3 = 0;
  86. for (int i = 0; i < temp - 1; i++) { //Мы рассматриваем пары различных элементов,
  87. //поэтому нам не надо смотреть последний элемент массива.
  88. for (int j = i + 1; j < temp; j++){ //Т.к. пары различных элементов, на второй позиции не смотрим первый элемент.
  89. if (F1[i] < F1[j]){ //Чтобы не было, например, {2,3} и {3,2}. Нужны различные множества.
  90. C2[temp2] = F1[i]; //Переводим в первый элемент кандидата часто встречающееся (k-1)-элементное множество.
  91. C2[temp2 + 1] = F1[j]; //Аналогично поступаем со второй позицией в кандидате.
  92. cout << endl << " {" << C2[temp2] << "," << C2[temp2 + 1] << "}"; //Выводим получившееся 2-элеметное множество.
  93. fout << endl << " {" << C2[temp2] << "," << C2[temp2 + 1] << "}";
  94. for (int z = 0; z < TransCount; z++){ //Сразу подсчитаем поддержку. Проверяем все чеки.
  95. if (T[z][num[i]] == 1 && T[z][num[j]] == 1){ //Используем запомненные номера столбиков.
  96. sup2[temp3]++;
  97. }; // Если в обоих столбиках 1, то увеличиваем поддержку.
  98. };
  99. cout << " sup=" << sup2[temp3]; //Выводим поддержку для данного 2-элементного множества.
  100. fout << " sup=" << sup2[temp3];
  101. temp2 = temp2 + 2; //Чтобы продолжить работать со следующей парой, т.е. следующими двумя позициями.
  102. temp3++; //Чтобы считать поддержку для следующей пары.
  103. }
  104. }
  105. }
  106. if (temp2 == 0){ cout << " не удалось составить множества." << endl; fout << " не удалось составить множества." << endl; };
  107. temp = 0; //Временная переменная
  108. for (int i = 0; i <= temp3; i++){ if (sup2[i] >= minsup) temp++; }; //Подсчитываем количество часто встречающихся для k=2.
  109. cout << endl<< "Удовлетворяющих элементов: " << temp << endl;
  110. fout << endl<< "Удовлетворяющих элементов: " << temp << endl;
  111. if (temp == 0){
  112. cout << "Больше часто встречающихся множеств не найдено." << endl;
  113. cout << "Результаты записаны в файл AprioriResult.txt." << endl;
  114. fout.close(); //Закрыли файл.
  115. system("pause");
  116. }
  117. else{ //Выводим сообщение,если таковых нет, останавливаем программу и закрываем файл. Иначе продолжаем:
  118. cout << "Эти элементы:" << endl;
  119. fout << "Эти элементы:" << endl;
  120. temp3 = 0;
  121. int temp4 = 0;
  122. int F2[temp2]; //Здесь temp2 отлично от прошлой размерности массива, оно получило новое значение
  123. // при работе с кандидатами. Отводит место под часто встречающиеся пары.
  124. int num2[temp2 << 1]; // Нам снова придётся запоминать номера столбцов, одна пара - один номер.
  125. //Для экономии использован побитовый сдвиг.
  126. for (int i = 0; i < temp2; i = i + 2){ //"Шагаем" через пару элементов, т.к. в С2 они тоже расположены парно.
  127. if (sup2[temp3] >= minsup) { //Если поддержка пары больше или равна минимальной,
  128. F2[temp4] = C2[i]; // то сохраняем первую позицию,
  129. num2[temp4] = int(i/2); // номер столбца для этого элемента,
  130. F2[temp4 + 1] = C2[i + 1]; // вторую позициюв паре
  131. num2[temp4 + 1] = int(i/2) + 1; // и номер столбца для второго элемента.
  132. cout << " {" << F2[temp4] << "," << F2[temp4 + 1] << "}" << endl; //Выводим на экран полученные двухэлементные множества.
  133. fout << " {" << F2[temp4] << "," << F2[temp4 + 1] << "}" << endl;
  134. temp4 = temp4 + 2; //Увеличиваем на два, т.к. заполняли парой.
  135. };
  136. temp3++; //На один, т.к. у пары одно значение поддержки, а не два.
  137.  
  138. };
  139.  
  140. /*Третий шаг*/
  141. cout << "Перейдём к третьему шагу, кандидаты: ";
  142. fout << "Кандидаты на третьем шаге:" << endl;
  143. int C3[temp3*3]; // Теперь k=3, т.е. будут рассматриваться тройки, поэтому для отведения памяти
  144. // количество двуэлементных множеств, которые станут здесь кандидатами, умножили втрое. На самом деле,
  145. // работать будет в основном количестве случаев, но не всегда, т.к. связано с комбинаторикой.
  146. int sup3[temp3]; //Этого количества вполне должно хватить для большинства случаев. Мы не оставляем константу,
  147. // чтобы не использовать избыток памяти. С другой стороны, мы ограничиваем себя в решениях.
  148. for (int i = 0; i < 100; i++){ sup3[i] = 0; }; // Очищаем от "мусора".
  149. temp2 = 0;
  150.  
  151. /*Отсортируем массив, чтобы исключить повторения во множествах в дальнейшем.*/
  152. int tmp = 0;
  153. for (int i = 0; i < temp4 - 1; ++i) { //Здесь используется обычная сортировка "пузырьком".
  154. for (int j = 0; j < temp4 - 1; ++j)
  155. {
  156. if (C2[j + 1] < C2[j]) //Если элемент меньше соседа, меняем их местами.
  157. {
  158. tmp = C2[j + 1]; //Это одна из причин, почему взят одномерный массив - удобство работы.
  159. C2[j + 1] = C2[j]; // Мы используем самые простые действия и операторы.
  160. C2[j] = tmp;
  161. }
  162. }
  163. };
  164.  
  165. temp3 = 0;
  166. tmp = 0;
  167. bool flag = false; //Он понадобится всего лишь один раз, чтобы отделить первый проход.
  168. for (int i = 0; i < temp4 - 2; i++) { //Аналогично со вторым шагом. Мы рассматриваем различные тройки,
  169. for (int j = i + 1; j < temp4 - 1; j++){ // поэтому на первой позиции никогда не будет два последних
  170. for (int g = i + 2; g < temp4; g++){ //кандидата и т.д. Используем сразу три ячейки и счётчика для них.
  171. if ((F2[i] < F2[j]) && (F2[j] < F2[g])){ //Будем рассматривать только те тройки, где элементы
  172. // в порядке возрастания. Чтобы все тройки были различными.
  173. if ((flag == true) && tmp == F2[i] + F2[j] + F2[g]){ goto rep; }; //Если проход не первый и сумма элементов
  174. // предыдущей тройки равна сумме элементов текущей, то "прыгаем" на метку.
  175. //Т.к. у нас идут по возрастанию, то суммы различных троек будут отличаться хотя бы на 1.
  176. // При учёте суммы нас не интересует положение чисел внутри множеств.
  177. C3[temp2] = F2[i]; //Сохранили первый элемент тройки, выбрав число из множества
  178. //из часто встречающихся 2-элементных множеств.
  179. C3[temp2 + 1] = F2[j]; // Сохранили второй элемент тройки.
  180. C3[temp2 + 2] = F2[g]; // Аналогично поступили с третьим элементов.
  181. tmp = F2[i] + F2[j] + F2[g]; //Подсчитали сумму, вес всей тройки.
  182. cout << endl << " {" << C3[temp2] << "," << C3[temp2 + 1] << "," << C3[temp2 + 2] << "}"; // Вывели полученное
  183. fout << endl << " {" << C3[temp2] << "," << C3[temp2 + 1] << "," << C3[temp2 + 2] << "}"; //трёхэлементное множество на экран.
  184. for (int z = 0; z < TransCount; z++){ // Подсчитаем для него поддержку.
  185. if (T[z][num2[i]] == 1 && T[z][num2[j]] == 1 && T[z][num2[g]] == 1){ //Используя сохранённые номера
  186. // столбцов, смотрим соответствующие значения в каждом чеке. Если все три 1, то
  187. sup3[temp3]++; // увеличиваем значение поддержки множества.
  188. };
  189. };
  190. cout << " sup=" << sup3[temp3]; //Вывели окончательно значение поддержки для данной тройки.
  191. fout << " sup=" << sup3[temp3];
  192. flag = true; //При первом проходе флаг меняется здесь с false на true.
  193. rep: temp2 = temp2 + 3; //Метка. Увеличиваем индекс ячеек, чтобы перейти к следующей тройке
  194. //(через два элемента от первого в данной тройке).
  195. temp3++; //Подсчитываем количество троек. Увеличиваем на один.
  196.  
  197. }
  198. }
  199. }
  200. }
  201. if (temp2 == 0){ cout << " не удалось составить множества." << endl; fout << " не удалось составить множества." << endl; };
  202. temp = 0;
  203. for (int i = 0; i <= temp3; i++){ //Меньше или равно, т.к. индексы начинались с нуля, а место в массиве - от 1.
  204. if (sup3[i] >= minsup) temp++;
  205. }; // Подсчитываем, сколько выделить памяти под часто встречающиеся трёхэлементные мн-ва.
  206. cout << endl<< "Удовлетворяющих элементов: " << temp << endl;
  207. fout << endl<< "Удовлетворяющих элементов: " << temp << endl;
  208. if (temp == 0){
  209. cout << "Больше часто встречающихся множеств не найдено." << endl;
  210. cout << "Результаты записаны в файл AprioriResult.txt." << endl;
  211. fout.close(); //Закрыли файл.
  212. system("pause");
  213. }
  214. else{ //Сообщение об ошибке и пауза, иначе ищем эти элементы.
  215. cout << "Эти элементы:" << endl;
  216. fout << "Эти элементы:" << endl;
  217. temp3 = 0;
  218. temp4 = 0;
  219. temp = temp * 3; //Т.к.это количество троек, т.е. самих ячеек надо в три раза больше.
  220. int F3[temp]; // Отводим память для самих элементов.
  221. int num3[temp]; // Отводим память для номеров столбцов для расчётов в будущем, четвёртом шаге.
  222. for (int i = 0; i < temp; i = i + 3){ //"Шагаем" по три. Мы работаем сразу со всеми позициями в каждом
  223. // трёхэлементном множестве.
  224. if (sup2[temp3] >= minsup) { // Если поддержка тройки больше или равна минимальной, то
  225. F3[temp4] = C3[i]; //Запомнили первый элемент тройки часто встречавшихся.
  226. num3[temp4] = i; // Номер столбца для этого элемента.
  227. F3[temp4 + 1] = C3[i + 1]; //Второй элемент
  228. num3[temp4 + 1] = i + 1; // и его номер,
  229. F3[temp4 + 2] = C3[i + 2]; // третий элемент,
  230. num3[temp4 + 2] = i + 2; // номер третьего элемента.
  231. cout << " {" << F3[temp4] << "," << F3[temp4 + 1] << "," << F3[temp4 + 2] << "}" << endl; //Вывели трёхэлементное множество.
  232. temp4 = temp4 + 3; //Увеличили индекс, чтобы перейти к следующей часто встречающейся тройке.
  233. };
  234. temp3++; //Увеличили номер рассматриваемой тройки. Понадобилось бы для следующего шага.
  235. };
  236. };
  237. };
  238. cout << "Работа программы закончена." << endl<<endl;
  239. fout.close(); //Закрыли файл.
  240. }
Add Comment
Please, Sign In to add comment