public List <PointF> solve()
        {
            // This is the solving function.
            // Over all we have O(|V|log|V|+|V|log|V|+|E|log|V|) which
            // reduces to O((E+V)log|V|).
            List <PointF> shortest  = new List <PointF>();
            List <data>   queue     = new List <data>();
            List <double> distances = new List <double>();
            List <int>    possible  = new List <int>();

            data[] match = new data[points.Count];

            // Make queue step. Takes O(|V|log(|V|)) because insert takes
            // O(log|V|) and we are inserting |V| nodes.
            for (int i = 0; i < points.Count; i++) // O(|V|)
            {
                possible.Add(i);
                if (i == startNodeIndex)
                {
                    distances.Add(0);
                    data temp = new data(points[i], 0, i, i);
                    match[i] = temp;
                    insert(ref queue, ref temp); // O(log|V|)
                }
                else
                {
                    distances.Add(double.MaxValue);
                    data temp = new data(points[i], double.MaxValue, i, i);
                    match[i] = temp;
                    insert(ref queue, ref temp); // O(log|V|)
                }
            }

            while (queue.Count > 0)
            {
                // This while loop takes O(|V|) because we pop one node off
                // the queue at a time.

                data u = deletemin(ref queue); // O(log|V|)
                possible[u.original] = -1;
                foreach (int v in adjacencyList[u.original])
                {
                    // This step can take at worst O(|E|).
                    if (possible[v] == -1)
                    {
                        continue;
                    }


                    double e_dist = eucl_dist(points[v], u.point);
                    if (distances[v] > u.dist + e_dist)
                    {
                        int i_v = match[v].location;
                        if (i_v < 0)
                        {
                            continue;
                        }

                        queue[i_v].dist = u.dist + e_dist;
                        distances[v]    = u.dist + e_dist;
                        if (final.ContainsKey(queue[i_v].point))
                        {
                            final[queue[i_v].point] = u.point;
                        }
                        else
                        {
                            final.Add(queue[i_v].point, u.point);
                        }
                        decrease_key(ref queue, i_v); // O(log|V|)
                    }
                }
            }
            try
            {
                PointF start = points[stopNodeIndex];
                PointF end   = final[points[stopNodeIndex]];

                shortest.Add(start);
                shortest.Add(end);

                while (end.X != points[startNodeIndex].X && end.Y != points[startNodeIndex].Y)
                {
                    start = end;
                    end   = final[start];
                    shortest.Add(end);
                }
            }
            catch (KeyNotFoundException e)
            {
                return(new List <PointF>());
            }

            return(shortest);
        }
        public data deletemin(ref List <data> queue)
        {
            // This function allows user to delete minimum from dinary heap.
            // Time complecity is a order of O(log|V|).
            // This is proven by the fact that a binary heap bubbles down
            // a value from a heap which is only log|V| deap.
            if (queue.Count <= 1)
            {
                data temp = queue[0];
                queue.RemoveAt(0);
                return(temp);
            }
            data min  = queue[0];
            data last = queue[queue.Count - 1];

            queue.RemoveAt(queue.Count - 1);
            queue[0]          = last;
            queue[0].location = 0;
            int index = 1;
            int index_n;

            while (true)
            {
                if ((2 * index) - 1 >= queue.Count)
                {
                    break;
                }
                data child;
                data left = queue[(2 * index) - 1];

                if ((2 * index + 1) - 1 >= queue.Count)
                {
                    child   = left;
                    index_n = 2 * index;
                }
                else
                {
                    data right = queue[(2 * index + 1) - 1];

                    if (left.dist <= right.dist)
                    {
                        child   = left;
                        index_n = 2 * index;
                    }
                    else
                    {
                        child   = right;
                        index_n = 2 * index + 1;
                    }
                }
                if (child.dist < queue[index - 1].dist)
                {
                    data temp = queue[index_n - 1];
                    queue[index_n - 1]          = queue[index - 1];
                    queue[index - 1]            = temp;
                    queue[index - 1].location   = index - 1;
                    queue[index_n - 1].location = index_n - 1;

                    index = index_n;
                }
                else
                {
                    break;
                }
            }

            return(min);
        }