-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAdjacencyList.cpp
More file actions
198 lines (170 loc) · 5.16 KB
/
AdjacencyList.cpp
File metadata and controls
198 lines (170 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <unordered_map>
#include "AdjacencyList.h"
using namespace std;
// prints the PageRank of all pages after p powerIterations in ascending
// alphabetical order of webpages and rounding rank to two decimal places
string AdjacencyList::PageRank(int power_iterations)
{
initializeRanks();
// Computes ranks through the passed in number of power iterations
computeRanks(power_iterations);
// printGraph();
// Generates and returns a string of ranks in alphabetical order of URLs
return displayRanks();
}
// Constructor that ensures that all maps are empty
AdjacencyList::AdjacencyList()
{
next_id = 1;
graph.clear();
id_to_url.clear();
url_to_id.clear();
ranks.clear();
out_degrees.clear();
}
// Initializes ranks to 1 / num_pages for future calculations
void AdjacencyList::initializeRanks()
{
int num_pages = url_to_id.size();
if (num_pages == 0)
return;
double initial_rank = 1.0 / num_pages;
for (auto entry : id_to_url)
{
int id = entry.first;
ranks[id] = initial_rank;
}
}
void AdjacencyList::computeRanks(int power_iterations)
{
// Makes sure that number of pages isnt 0
int num_pages = url_to_id.size();
if (num_pages == 0)
return;
unordered_map<int, double> temp_ranks;
for (int iter = 0; iter < power_iterations - 1; iter++)
{
// Resets temp_ranks for the current iteration
for (auto entry : ranks)
{
int id = entry.first;
temp_ranks[id] = 0.0;
}
// Distributes ranks to neighbors
for (auto entry : ranks)
{
int from_id = entry.first;
double current_rank = entry.second;
if (out_degrees[from_id] > 0)
{
double rank_share = current_rank / out_degrees[from_id];
for (int to_id : graph[from_id])
{
temp_ranks[to_id] += rank_share;
}
}
}
// Updates ranks with temp_ranks for the next power iteration
for (auto entry : temp_ranks)
{
int id = entry.first;
ranks[id] = entry.second;
}
// Debug: Calculates total rank after each iteration
/*
double total_rank = 0.0;
for (auto entry : ranks)
{
total_rank += entry.second;
}
cout << "Iteration " << iter + 1 << " Total Rank: " << total_rank << endl;
// Debug: Prints ranks after each iteration
cout << "After iteration " << iter + 1 << ":\n";
for (auto entry : ranks)
{
cout << id_to_url[entry.first] << ": " << entry.second << "\n";
}
cout << "\n";
*/
}
}
int AdjacencyList::getOrCreateID(string url)
{
// Checks if URL already has an ID
if (url_to_id.find(url) == url_to_id.end())
{
// Assigns new ID
url_to_id[url] = next_id;
id_to_url[next_id] = url;
next_id++;
}
return url_to_id[url];
}
void AdjacencyList::addEdge(string from, string to)
{
// Gets or create unique IDs for the from and to URLs
int from_id = getOrCreateID(from);
int to_id = getOrCreateID(to);
// Adds the to page to the adjacency list of the from page
graph[from_id].push_back(to_id);
// Updates the out-degree of the from page
out_degrees[from_id]++;
}
string AdjacencyList::displayRanks()
{
// Creates a vector of pairs to hold URL and its corresponding rank
vector<pair<string, double>> url_ranks;
// Populates the vector with URLs and their ranks
for (auto entry : id_to_url)
{
int id = entry.first;
string url = entry.second;
double rank = ranks.at(id);
url_ranks.emplace_back(url, rank);
}
// Sorts the vector by URL in ascending alphabetical order
sort(url_ranks.begin(), url_ranks.end());
// Prints each URL and its rank, rounded to two decimal places and also stores into a stringstream for returning purposes
ostringstream oss;
for (auto url_rank : url_ranks)
{
cout << url_rank.first << " " << fixed << setprecision(2) << url_rank.second << "\n";
oss << url_rank.first << " " << fixed << setprecision(2) << url_rank.second << "\n";
}
return oss.str();
}
// For Catch testing purposes
string AdjacencyList::parseInput(string input)
{
istringstream iss(input);
int num_edges, power_iterations;
// Read the number of edges and power iterations
iss >> num_edges >> power_iterations;
// Read each edge and add it to the graph
string from, to;
for (int i = 0; i < num_edges; i++)
{
iss >> from >> to;
addEdge(from, to);
}
return PageRank(power_iterations);
}
// For debugging purposes making sure everything was associated correctly
void AdjacencyList::printGraph()
{
for (auto entry : graph)
{
int from_id = entry.first;
cout << "From " << id_to_url[from_id] << " to: ";
for (int to_id : entry.second)
{
cout << id_to_url[to_id] << " ";
}
cout << endl;
}
}