I am trying to implement A* search algorithm with priority_queues and I have drawn the output on the console with opengl.
I got this output: Final path with A star
Where the cells in gray weren't visited, in yellow were visited and the final path in blue.
I think that the cells that were visited should be less and closer to the path, or I am wrong?
I computed the path with the following code:
list<Node*> compute_path_A_star(Node* start, Node* goal)
{
priority_queue< nodeDistance, vector< nodeDistance >, CompareDist> pq;
vector<Node*> came_from;
vector<float> cost_so_far;
nodeDistance first;
first.node = start;
first.distance = 0.0f;
pq.push(first);
came_from.resize(20 * 20, nullptr);
cost_so_far.resize(20 * 20, 9999.0f);
cost_so_far[start->x + 20 * start->y] = 0.0f;
//Compute where we came from for every location that’s visited
int i = 0;
while (!pq.empty())
{
nodeDistance temp = pq.top();
pq.pop();
Node* current_node = temp.node;
current_node = get_node(current_node->x, current_node->y);
if (current_node == goal) break;
for (auto n : current_node->neighbours)
{
float new_cost = cost_so_far[current_node->x + 20 * current_node->y] + n->cost;
if (new_cost < cost_so_far[n->x + 20 * n->y])
{
cost_so_far[n->x + 20 * n->y] = new_cost;
came_from[n->x + 20 * n->y] = current_node;
nodeDistance newNode;
newNode.node = n;
newNode.distance = new_cost + heuristic(n, goal);
pq.push(newNode);
}
}
}
#pragma region Create the path (start -> goal)
Node* current = new Node();
current = goal;
list<Node*> path;
path.push_back(current);
while (current != start)
{
current = came_from[current->x + 20 * current->y];
path.push_back(current);
}
path.reverse();
#pragma endregion
return path;
}
I used Manhattan distance for the heuristic:
float heuristic(Node* a, Node* b)
{
//Manhattan distance on a square grid
return (abs(a->x - b->x) + abs(a->y - b->y));
}
nodeDistance is a struct:
struct nodeDistance
{
Node* node;
float distance;
};
And for the comparision in the priority queue I defined this class:
class CompareDist
{
public:
bool operator()(nodeDistance& n1, nodeDistance& n2)
{
if (n1.distance > n2.distance)
return true;
else
return false;
}
};
I defined each node as:
struct Node
{
int x, y;
float cost;
Node* parent;
list<Node*> neighbours;
};
And the graph:
list<Node*> Graph;
Edit 1:
For the A star implementation, I was based on this page http://www.redblobgames.com/pathfinding/a-star/introduction.html.
There is something that I missed? Thanks!
Edit 2:
I have inserted some obstacles (dark-gray cells) and waypoints (pink cells) on the scene. In red the goal cell
Related
I'm trying to explore the binary tree.
However, I have to implement recursive functions nonrecursively.
I've searched several ways to convert recursion to nonrecursive.
But it doesn't seem to apply to my code.
I wonder if I can convert my code to non-recursive and how I can convert it.
This is my code(recursive function)
const NODE* getNN(const float pos[DIM], const NODE* cur, int depth) {
if (!cur) return nullptr;
bool flag = pos[depth % DIM] < cur->pos[depth % DIM];
NODE* next{ flag ? cur->left : cur->right };
NODE* other{ flag ? cur->right : cur->left };
const NODE* temp = getNN(pos, next, depth + 1);
const NODE* best{ closest(pos, temp, cur) };
float r = this->distance(pos, best->pos);
float dr = pos[depth % DIM] - cur->pos[depth % DIM];
if (r >= dr * dr) {
temp = getNN(pos, other, depth + 1);
best = closest(pos, temp, best);
}
return best;
}
Here is what I expected
const NODE* getNN_NonRecur(const float pos[DIM])
It's been resolved it. Thank you for advice.
const NODE* getNN_NR(const float pos[DIM])
{
std::stack<std::pair<std::pair<NODE*, NODE*>, unsigned int>> st;
composeStack(st, pos, this->root, 0);
const NODE* best{ st.top().first.first };
while (!st.empty())
{
auto e = st.top(); st.pop();
if (!e.first.first) continue;
best = closest(pos, best, e.first.first);
float r = distance(pos, best->pos);
float dr = pos[e.second % DIM] - e.first.first->pos[e.second % DIM];
if (r >= dr * dr) {
composeStack(st, pos, e.first.second, e.second);
best = closest(pos, st.top().first.first, best);
}
}
return best;
}
void composeStack(std::stack<std::pair<std::pair<NODE*, NODE*>, unsigned int>>& st,
const float pos[DIM],
NODE* node, unsigned int depth)
{
NODE* cur = node;
st.push({ {node, nullptr}, depth });
while (cur) {
auto e = st.top();
cur = e.first.first; depth = e.second;
bool flag = pos[depth % DIM] < cur->pos[depth % DIM];
NODE* next{ flag ? cur->left : cur->right };
NODE* other{ flag ? cur->right : cur->left };
st.push(std::pair<std::pair
<NODE*, NODE*>, unsigned int>({ next, other }, depth + 1));
cur = next;
}
}
I am trying to make the Dijkstra algorithm to take input from the text file. I found this example (https://www.programiz.com/dsa/dijkstra-algorithm) for Dijkstra, which does exactly what I need - finds the shortest path between two nodes and prints it together with a cost.
How can I fill the graph from the given text file? Thanks in advance for any replies.
Code example, updated to use decimal weights:
// Dijkstra's Algorithm in C++
#include <iostream>
#include <vector>
#include <limits.h>
using namespace std;
void DijkstrasTest();
int main() {
DijkstrasTest();
return 0;
}
class Node;
class Edge;
void Dijkstras();
vector<Node*>* AdjacentRemainingNodes(Node* node);
Node* ExtractSmallest(vector<Node*>& nodes);
double Distance(Node* node1, Node* node2);
bool Contains(vector<Node*>& nodes, Node* node);
void PrintShortestRouteTo(Node* destination);
vector<Node*> nodes;
vector<Edge*> edges;
class Node {
public:
Node(char id)
: id(id), previous(NULL), distanceFromStart(INT_MAX) {
nodes.push_back(this);
}
public:
char id;
Node* previous;
double distanceFromStart;
};
class Edge {
public:
Edge(Node* node1, Node* node2, double distance)
: node1(node1), node2(node2), distance(distance) {
edges.push_back(this);
}
bool Connects(Node* node1, Node* node2) {
return (
(node1 == this->node1 &&
node2 == this->node2) ||
(node1 == this->node2 &&
node2 == this->node1));
}
public:
Node* node1;
Node* node2;
double distance;
};
///////////////////
void DijkstrasTest() {
Node* a = new Node('a');
Node* b = new Node('b');
Node* c = new Node('c');
Node* d = new Node('d');
Node* e = new Node('e');
Node* f = new Node('f');
Node* g = new Node('g');
Edge* e1 = new Edge(a, c, 1.74);
Edge* e2 = new Edge(a, d, 2.156);
Edge* e3 = new Edge(b, c, 2.516);
Edge* e4 = new Edge(c, d, 1.321);
Edge* e5 = new Edge(b, f, 3.51);
Edge* e6 = new Edge(c, e, 3.11);
Edge* e7 = new Edge(e, f, 2.2);
Edge* e8 = new Edge(d, g, 1.1);
Edge* e9 = new Edge(g, f, 1.5);
a->distanceFromStart = 0; // set start node
Dijkstras();
PrintShortestRouteTo(f);
}
///////////////////
void Dijkstras() {
while (nodes.size() > 0) {
Node* smallest = ExtractSmallest(nodes);
vector<Node*>* adjacentNodes =
AdjacentRemainingNodes(smallest);
const int size = adjacentNodes->size();
for (int i = 0; i < size; ++i) {
Node* adjacent = adjacentNodes->at(i);
double distance = Distance(smallest, adjacent) +
smallest->distanceFromStart;
if (distance < adjacent->distanceFromStart) {
adjacent->distanceFromStart = distance;
adjacent->previous = smallest;
}
}
delete adjacentNodes;
}
}
// Find the node with the smallest distance,
// remove it, and return it.
Node* ExtractSmallest(vector<Node*>& nodes) {
int size = nodes.size();
if (size == 0) return NULL;
int smallestPosition = 0;
Node* smallest = nodes.at(0);
for (int i = 1; i < size; ++i) {
Node* current = nodes.at(i);
if (current->distanceFromStart <
smallest->distanceFromStart) {
smallest = current;
smallestPosition = i;
}
}
nodes.erase(nodes.begin() + smallestPosition);
return smallest;
}
// Return all nodes adjacent to 'node' which are still
// in the 'nodes' collection.
vector<Node*>* AdjacentRemainingNodes(Node* node) {
vector<Node*>* adjacentNodes = new vector<Node*>();
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
Node* adjacent = NULL;
if (edge->node1 == node) {
adjacent = edge->node2;
} else if (edge->node2 == node) {
adjacent = edge->node1;
}
if (adjacent && Contains(nodes, adjacent)) {
adjacentNodes->push_back(adjacent);
}
}
return adjacentNodes;
}
// Return distance between two connected nodes
double Distance(Node* node1, Node* node2) {
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
if (edge->Connects(node1, node2)) {
return edge->distance;
}
}
return -1; // should never happen
}
// Does the 'nodes' vector contain 'node'
bool Contains(vector<Node*>& nodes, Node* node) {
const int size = nodes.size();
for (int i = 0; i < size; ++i) {
if (node == nodes.at(i)) {
return true;
}
}
return false;
}
///////////////////
void PrintShortestRouteTo(Node* destination) {
Node* previous = destination;
cout << "Distance from start: "
<< destination->distanceFromStart << endl;
while (previous) {
cout << previous->id << " ";
previous = previous->previous;
}
cout << endl;
}
// these two not needed
vector<Edge*>* AdjacentEdges(vector<Edge*>& Edges, Node* node);
void RemoveEdge(vector<Edge*>& Edges, Edge* edge);
vector<Edge*>* AdjacentEdges(vector<Edge*>& edges, Node* node) {
vector<Edge*>* adjacentEdges = new vector<Edge*>();
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
if (edge->node1 == node) {
cout << "adjacent: " << edge->node2->id << endl;
adjacentEdges->push_back(edge);
} else if (edge->node2 == node) {
cout << "adjacent: " << edge->node1->id << endl;
adjacentEdges->push_back(edge);
}
}
return adjacentEdges;
}
void RemoveEdge(vector<Edge*>& edges, Edge* edge) {
vector<Edge*>::iterator it;
for (it = edges.begin(); it < edges.end(); ++it) {
if (*it == edge) {
edges.erase(it);
return;
}
}
}
Fragment of the input file, number of lines is unknown:
source_id,target_id,weight
1,2,0.17
2,3,0.13
3,4,0.15
3,5,0.02
4,5,0.09
5,2,0.01
Your input is a list of node links.
Your algorithm requires an adjacency matrix, which is a vector containing vectors of the nodes adjacent to each node.
To convert from a list of links to an adjacency matrix, you need a graph class that among other things will populate the adjacency martrix using a function such as AddLink( int src, int dst, double cost )
There are many such classes available for you to copy or modify to your particular situation. I'll mention just one: PathFinder
Below is the PathFinder code to do the conversion. You will need something slightly different to handle the format of your file. Here is the format that PathFinder is reading
while (std::getline(myFile, line))
{
std::cout << line << "\n";
auto token = ParseSpaceDelimited(line);
if (!token.size())
continue;
switch (token[0][0])
{
case 'g':
if (myFinder.linkCount())
throw std::runtime_error("cPathFinderReader:: g ( directed ) must occurr before any links");
myFinder.directed();
break;
case 'l':
if (weights && (token.size() != 4))
throw std::runtime_error("cPathFinder::read bad link line");
else if (3 > token.size() || token.size() > 4)
throw std::runtime_error("cPathFinder::read bad link line");
if (weights)
cost = atof(token[3].c_str());
else
cost = 1;
if (cost < maxNegCost)
maxNegCost = cost;
myFinder.addLink(
token[1],
token[2],
cost);
break;
case 's':
if (token.size() != 2)
throw std::runtime_error("cPathFinder::read bad start line");
myFinder.start(token[1]);
break;
case 'e':
if (token.size() != 2)
throw std::runtime_error("cPathFinder::read bad end line");
myFinder.end(token[1]);
break;
}
}
I have a breadth first search to find the best solution to an 8 puzzle. In order to make sure I don't execute the same function call on the same puzzle move I have created a tree structure. It doesn't store the puzzle, just creates a pathway in the tree for the 9 values for the 9 slots in the puzzle. Here is the code:
static const int NUM_NODES = 9;
class TreeNode
{
public:
TreeNode *mylist[NUM_NODES];
TreeNode()
{
for (int x = 0; x < NUM_NODES; ++x)
mylist[x] = nullptr;
}
};
class Tree
{
private:
TreeNode *mynode;
public:
Tree()
{
mynode = new Node();
}
bool checkOrCreate(const Puzzle &p1)
{
Node *current_node = mynode;
bool found = true;
for (int x = 0; x < PUZZLE_SIZE; ++x)
{
for (int y = 0; y < PUZZLE_SIZE; ++y)
{
int index_value = p1.grid[x][y];
if (current_node->mylist[index_value] == nullptr)
{
found = false;
current_node->mylist[index_value] = new Node();
current_node = current_node->mylist[index_value];
}
else
current_node = current_node->mylist[index_value];
}
}
return found;
}
};
static Node* depth_Limited_Search(Problem &problem, int limit)
{
mylist.reset();
return recursive_Depth_Search(&Node(problem.initial_state, nullptr, START), problem, limit);
}
static Node *recursive_Depth_Search(Node *node, Problem &problem, int limit)
{
if (problem.goal_state == node->state)
return node;
else if (limit == 0)
return nullptr;
if (mylist.checkOrCreate(node->state)) //if state already exists, delete the node and return nullptr
return nullptr;
std::unique_ptr<int> xy(node->state.getCoordinates());
int xOfSpace = xy.get()[0];
int yOfSpace = xy.get()[1];
set <Action> actions = problem.actions(node->state); //gets actions
for (auto it = begin(actions); it != end(actions); ++it)
{
Action action = *it;
Node &child = child_node(problem, *node, action);
Node *answer = recursive_Depth_Search(&child, problem, limit - 1);
if (answer != nullptr)
return answer;
}
return nullptr;
}
static Node& child_node(Problem problem, Node &parent, Action action)
{
Node &child = *(new Node());
child.state = problem.result(parent.state, action);
child.parent = &parent;
child.action = action;
child.path_cost = parent.path_cost + problem.step_cost(parent.state, action);
return child;
}
Puzzle& result(const Puzzle &state, Action action)
{
// return a puzzle in the new state after perfroming action
Puzzle &new_state = *(new Puzzle(state));
int r = state.getCoordinates()[0], c = state.getCoordinates()[1];
if (action == UP)
new_state.swap(r, c, r - 1, c);
else if (action == RIGHT)
new_state.swap(r, c, r, c + 1);
else if (action == DOWN)
new_state.swap(r, c, r + 1, c);
else if (action == LEFT)
new_state.swap(r, c, r, c - 1);
return new_state;
}
I've used this on breadth and also on depth limited search using recursion to solve. Using this structure to store all the possible solutions for these algorithms takes a long time. I believe it has something to do with the allocation taking time. Is that the reason? I was thinking of trying to just create a lump of memory, and then assigning a node that address of memory instead of letting the program do it. Would that be the best solution, and how would I do that? (Since I've used this on multiple searches and they all take a long time to perform I haven't included that code.)
I am using the code in this page. Recently I would like to compile with -o3 flag on my mac terminal. It turns out showing the error message, but the code can be successfully complied with -o flag without any errors.
Here are my code
// C / C++ program for Dijkstra's shortest path algorithm for adjacency
// list representation of graph
// C / C++ program for Dijkstra's shortest path algorithm for adjacency
// list representation of graph
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// A structure to represent a node in adjacency list
struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
};
// A structure to represent an adjacency liat
struct AdjList
{
struct AdjListNode *head; // pointer to head node of list
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
int V;
struct AdjList* array;
};
// A utility function to create a new adjacency list node
struct AdjListNode* newAdjListNode(int dest, int weight)
{
struct AdjListNode* newNode =
(struct AdjListNode*) malloc(sizeof(struct AdjListNode));
newNode->dest = dest;
newNode->weight = weight;
newNode->next = NULL;
return newNode;
}
// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
graph->V = V;
// Create an array of adjacency lists. Size of array will be V
graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));
// Initialize each adjacency list as empty by making head as NULL
for (int i = 0; i < V; ++i)
graph->array[i].head = NULL;
return graph;
}
// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src, int dest, int weight)
{
// Add an edge from src to dest. A new node is added to the adjacency
// list of src. The node is added at the begining
struct AdjListNode* newNode = newAdjListNode(dest, weight);
newNode->next = graph->array[src].head;
graph->array[src].head = newNode;
// Since graph is undirected, add an edge from dest to src also
newNode = newAdjListNode(src, weight);
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;
}
// Structure to represent a min heap node
struct MinHeapNode
{
int v;
int dist;
};
// Structure to represent a min heap
struct MinHeap
{
int size; // Number of heap nodes present currently
int capacity; // Capacity of min heap
int *pos; // This is needed for decreaseKey()
struct MinHeapNode **array;
};
// A utility function to create a new Min Heap Node
struct MinHeapNode* newMinHeapNode(int v, int dist)
{
struct MinHeapNode* minHeapNode =
(struct MinHeapNode*) malloc(sizeof(struct MinHeapNode));
minHeapNode->v = v;
minHeapNode->dist = dist;
return minHeapNode;
}
// A utility function to create a Min Heap
struct MinHeap* createMinHeap(int capacity)
{
struct MinHeap* minHeap =
(struct MinHeap*) malloc(sizeof(struct MinHeap));
minHeap->pos = (int *)malloc(capacity * sizeof(int));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array =
(struct MinHeapNode**) malloc(capacity * sizeof(struct MinHeapNode*));
return minHeap;
}
// A utility function to swap two nodes of min heap. Needed for min heapify
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b)
{
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}
// A standard function to heapify at given idx
// This function also updates position of nodes when they are swapped.
// Position is needed for decreaseKey()
void minHeapify(struct MinHeap* minHeap, int idx)
{
int smallest, left, right;
smallest = idx;
left = 2 * idx + 1;
right = 2 * idx + 2;
if (left < minHeap->size &&
minHeap->array[left]->dist < minHeap->array[smallest]->dist )
smallest = left;
if (right < minHeap->size &&
minHeap->array[right]->dist < minHeap->array[smallest]->dist )
smallest = right;
if (smallest != idx)
{
// The nodes to be swapped in min heap
MinHeapNode *smallestNode = minHeap->array[smallest];
MinHeapNode *idxNode = minHeap->array[idx];
// Swap positions
minHeap->pos[smallestNode->v] = idx;
minHeap->pos[idxNode->v] = smallest;
// Swap nodes
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
// A utility function to check if the given minHeap is ampty or not
int isEmpty(struct MinHeap* minHeap)
{
return minHeap->size == 0;
}
// Standard function to extract minimum node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
if (isEmpty(minHeap))
return NULL;
// Store the root node
struct MinHeapNode* root = minHeap->array[0];
// Replace root node with last node
struct MinHeapNode* lastNode = minHeap->array[minHeap->size - 1];
minHeap->array[0] = lastNode;
// Update position of last node
minHeap->pos[root->v] = minHeap->size-1;
minHeap->pos[lastNode->v] = 0;
// Reduce heap size and heapify root
--minHeap->size;
minHeapify(minHeap, 0);
return root;
}
// Function to decreasy dist value of a given vertex v. This function
// uses pos[] of min heap to get the current index of node in min heap
void decreaseKey(struct MinHeap* minHeap, int v, int dist)
{
// Get the index of v in heap array
int i = minHeap->pos[v];
// Get the node and update its dist value
minHeap->array[i]->dist = dist;
// Travel up while the complete tree is not hepified.
// This is a O(Logn) loop
while (i && minHeap->array[i]->dist < minHeap->array[(i - 1) / 2]->dist)
{
// Swap this node with its parent
minHeap->pos[minHeap->array[i]->v] = (i-1)/2;
minHeap->pos[minHeap->array[(i-1)/2]->v] = i;
swapMinHeapNode(&minHeap->array[i], &minHeap->array[(i - 1) / 2]);
// move to parent index
i = (i - 1) / 2;
}
}
// A utility function to check if a given vertex
// 'v' is in min heap or not
bool isInMinHeap(struct MinHeap *minHeap, int v)
{
if (minHeap->pos[v] < minHeap->size)
return true;
return false;
}
// The main function that calulates distances of shortest paths from src to all
// vertices. It is a O(ELogV) function
void dijkstra(struct Graph* graph, int src)
{
int V = graph->V;// Get the number of vertices in graph
int dist[V]; // dist values used to pick minimum weight edge in cut
// minHeap represents set E
struct MinHeap* minHeap = createMinHeap(V);
// Initialize min heap with all vertices. dist value of all vertices
for (int v = 0; v < V; ++v)
{
dist[v] = INT_MAX;
minHeap->array[v] = newMinHeapNode(v, dist[v]);
minHeap->pos[v] = v;
}
// Make dist value of src vertex as 0 so that it is extracted first
minHeap->array[src] = newMinHeapNode(src, dist[src]);
minHeap->pos[src] = src;
dist[src] = 0;
decreaseKey(minHeap, src, dist[src]);
// Initially size of min heap is equal to V
minHeap->size = V;
// In the followin loop, min heap contains all nodes
// whose shortest distance is not yet finalized.
while (!isEmpty(minHeap))
{
// Extract the vertex with minimum distance value
struct MinHeapNode* minHeapNode = extractMin(minHeap);
int u = minHeapNode->v; // Store the extracted vertex number
// Traverse through all adjacent vertices of u (the extracted
// vertex) and update their distance values
struct AdjListNode* pCrawl = graph->array[u].head;
while (pCrawl != NULL)
{
int v = pCrawl->dest;
// If shortest distance to v is not finalized yet, and distance to v
// through u is less than its previously calculated distance
if (isInMinHeap(minHeap, v) && dist[u] != INT_MAX &&
pCrawl->weight + dist[u] < dist[v])
{
dist[v] = dist[u] + pCrawl->weight;
// update distance value in min heap also
decreaseKey(minHeap, v, dist[v]);
}
pCrawl = pCrawl->next;
}
}
free(minHeap->pos);
for (int i=0;i<minHeap->size;i++) {
free(minHeap->array[i]);
}
free(minHeap->array);
free(minHeap);
}
// Driver program to test above functions
int main()
{
// create the graph given in above fugure
int V = 20000,t=0;
while (t!=10) {
struct Graph* graph = createGraph(V);
for (int i=0; i<10000; i++) {
for(int j=10000;j<20000;j++){
addEdge(graph, 0, i, i);
addEdge(graph, i, j, i+j);
}
}
dijkstra(graph, 0);
for(int d=0; d<graph->V; d++)
{
AdjListNode *p1=graph->array[d].head, *p2;
while(p1)
{
p2=p1;
p1=p1->next;
free(p2);
}
}
free(graph->array);
free(graph);
t++;
}
return 0;
}
Here is the error message
seshunsakaitekiMacBook-Pro:test Daniel$ g++ -o3 TEST main.cpp
ld: can't link with a main executable file 'TEST' for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The lowercase -o flag specifies the output file.
The uppercase -O flag specifies the optimization level.
You may have intended to use:
g++ -O3 -o TEST main.cpp
Instead of:
g++ -o3 TEST main.cpp
Hey I have to find the most eficient way to print a number by giving the postion. The input is like this:
8 (N-> N Numbers)
INS 100 (Add 100 to the tree)
INS 200 (Add 200 to the tree)
INS 300 (Add 300 to the tree)
REM 200 (Remove the number 200 from the tree)
PER 1 (Have to output the biggest number in the tree-> Shoud print 300)
INS 1000 (Add 1000 to the tree)
PER 1 ((Have to output the biggest number in the tree-> Shoud print 1000))
PER 2 (I have to output the second biggest number so: 300)
I have a way to print like this, but is very slow and I have to maintain a O(N * log(N)).
Here is my full code
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
// An AVL tree node
struct node
{
int key;
struct node *left;
struct node *right;
int height;
};
// A utility function to get maximum of two integers
int max(int a, int b);
// A utility function to get height of the tree
int height(struct node *N)
{
if (N == NULL)
return 0;
return N->height;
}
// A utility function to get maximum of two integers
int max(int a, int b)
{
return (a > b)? a : b;
}
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct node* newNode(int key)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return(node);
}
// A utility function to right rotate subtree rooted with y
// See the diagram given above.
struct node *rightRotate(struct node *y)
{
struct node *x = y->left;
struct node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Return new root
return x;
}
// A utility function to left rotate subtree rooted with x
// See the diagram given above.
struct node *leftRotate(struct node *x)
{
struct node *y = x->right;
struct node *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
// Get Balance factor of node N
int getBalance(struct node *N)
{
if (N == NULL)
return 0;
return height(N->left) - height(N->right);
}
struct node* insert(struct node* node, int key)
{
/* 1. Perform the normal BST rotation */
if (node == NULL)
return(newNode(key));
if (key < node->key)
node->left = insert(node->left, key);
else
node->right = insert(node->right, key);
/* 2. Update height of this ancestor node */
node->height = max(height(node->left), height(node->right)) + 1;
/* 3. Get the balance factor of this ancestor node to check whether
this node became unbalanced */
int balance = getBalance(node);
// If this node becomes unbalanced, then there are 4 cases
// Left Left Case
if (balance > 1 && key < node->left->key)
return rightRotate(node);
// Right Right Case
if (balance < -1 && key > node->right->key)
return leftRotate(node);
// Left Right Case
if (balance > 1 && key > node->left->key)
{
node->left = leftRotate(node->left);
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && key < node->right->key)
{
node->right = rightRotate(node->right);
return leftRotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
/* Given a non-empty binary search tree, return the node with minimum
key value found in that tree. Note that the entire tree does not
need to be searched. */
struct node * minValueNode(struct node* node)
{
struct node* current = node;
/* loop down to find the leftmost leaf */
while (current->left != NULL)
current = current->left;
return current;
}
struct node* apagaNode(struct node* root, int key)
{
// STEP 1: PERFORM STANDARD BST DELETE
if (root == NULL)
return root;
// If the key to be deleted is smaller than the root's key,
// then it lies in left subtree
if ( key < root->key )
root->left = apagaNode(root->left, key);
// If the key to be deleted is greater than the root's key,
// then it lies in right subtree
else if( key > root->key )
root->right = apagaNode(root->right, key);
// if key is same as root's key, then This is the node
// to be deleted
else
{
// node with only one child or no child
if( (root->left == NULL) || (root->right == NULL) )
{
struct node *temp = root->left ? root->left : root->right;
// No child case
if(temp == NULL)
{
temp = root;
root = NULL;
}
else // One child case
*root = *temp; // Copy the contents of the non-empty child
free(temp);
}
else
{
// node with two children: Get the inorder successor (smallest
// in the right subtree)
struct node* temp = minValueNode(root->right);
// Copy the inorder successor's data to this node
root->key = temp->key;
// Delete the inorder successor
root->right = apagaNode(root->right, temp->key);
}
}
// If the tree had only one node then return
if (root == NULL)
return root;
// STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
root->height = max(height(root->left), height(root->right)) + 1;
// STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether
// this node became unbalanced)
int balance = getBalance(root);
// If this node becomes unbalanced, then there are 4 cases
// Left Left Case
if (balance > 1 && getBalance(root->left) >= 0)
return rightRotate(root);
// Left Right Case
if (balance > 1 && getBalance(root->left) < 0)
{
root->left = leftRotate(root->left);
return rightRotate(root);
}
// Right Right Case
if (balance < -1 && getBalance(root->right) <= 0)
return leftRotate(root);
// Right Left Case
if (balance < -1 && getBalance(root->right) > 0)
{
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
int imprime(struct node *root,int targetPos,int curPos)
{
if(root != NULL)
{
int newPos = imprime(root->left, targetPos, curPos);
newPos++;
if (newPos == targetPos)
{
printf("%d\n", root->key);
}
return imprime(root->right, targetPos, newPos);
}
else
{
return curPos;
}
}
int main()
{
struct node *root = NULL;
int total=0;
int n,b;
string a;
cin >> n;
for (int i=0; i<n; i++)
{
cin >> a >> b;
if(a=="INS")
{root = insert(root, b);total=total+1;}
else
if(a=="REM")
{root = apagaNode(root, b);total=total-1;}
else
imprime(root, total-b+1, 0);
}
return 0;
}
The way I found to print the values:
int imprime(struct node *root,int targetPos,int curPos)
{
if(root != NULL)
{
int newPos = imprime(root->left, targetPos, curPos);
newPos++;
if (newPos == targetPos)
{
printf("%d\n", root->key);
}
return imprime(root->right, targetPos, newPos);
}
else
{
return curPos;
}
}
Problem is that this function is very slow, and I can't use it. How is the best way to print by a given postion like this? (A heard about, counting n_nodes, and during the rotations I have to incremennt, decrement, i realy did not understand. Help me please! Give some tips, and advices) (PS: I'm not an expert with this kind of algorithms)
The advice you heard is correct: you should add a node counter to your node structure:
struct node
{
int key;
struct node *left;
struct node *right;
int height;
int n_nodes;
};
It should hold the number of nodes in the tree. Assuming it's correct, you can improve the algorithm for finding a node with a target position: it will know exactly in which branch of the tree to look (left or right), which will make the search faster (current imprime implementation is O(n)).
So, how to make it so the n_nodes field holds the right value? Fortunately, you already have an example: height. Look where your existing code changes it; these are roughly the places where you have to update n_nodes, too. Most of them are trivial (just add 1 to it); the more interesting ones are the rotation functions:
struct node *rightRotate(struct node *y)
{
struct node *x = y->left;
struct node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Update numbers of nodes
x->n_nodes = ...;
y->n_nodes = ...;
T2->n_nodes = ...;
// Return new root
return x;
}
So it transforms the tree like this:
y x
/ \ / \
x D A y
/ \ ==> / \
A T2 T2 D
/ \ / \
B C B C
Here A, B, C and D are trees whose sizes your program knows; let's denote their sizes as a, b, c and d. So the transformation changes these sizes like this:
size of x: from a+b+c+2 to a+b+c+d+3
size of y: from a+b+c+d+3 to b+c+d+2
size of T2: unchanged
So just transform this to code.