I don't know what the rest of the code looks like, if there is any structure for each tile. Anyway while you are generating x and y positions during for loop, the heights for all tiles must be stored somewhere. For example in std::vector<int> m_heightmap[width * height - 1].
Then just add height to all y axis:
quad[0].position = sf::Vector2f(i * tileSize.x, j * tileSize.y + m_heightmap[this_tile_index]);
quad[1].position = sf::Vector2f((i + 1) * tileSize.x, j * tileSize.y + m_heightmap[this_tile_index + 1]);
quad[2].position = sf::Vector2f((i + 1) * tileSize.x, (j + 1) * tileSize.y + m_heightmap[this_tile_index + 1 + row_bellow]);
quad[3].position = sf::Vector2f(i * tileSize.x, (j + 1) * tileSize.y + m_heightmap[index_of_tile_row_bellow]);
You must be carefull about index, it will be different in each line because quads have separated coordinates and you're counting with neighboring tiles which follow the changed height. It is probably not the best described, but the logic behind is straightforward.