Pointers enable efficient composite data structures
You have something like this (using pseudocode C++):
class Node
bool visited
double key
Node* pi
vector<pair<Node*, double>> adjacent //adjacent nodes and edge weights
//and extra fields needed for PriorityQueue data structure
// - a clean way to do this is to use CRTP for defining the base
// PriorityQueue node class, then inherit your graph node from that
class Graph
vector<Node*> vertices
CRTP: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
The priority queue Q in the algorithm contains items of type Node*, where ExtractMin gets you the Node* with minimum key.
The reason you don't have to do any linear search is because, when you get u = ExtractMin(Q), you have a Node*. So u->adjacent gets you both the v's in G.Adj[u] and the w(u,v)'s in const time per adjacent node. Since you have a pointer v to the priority queue node (which is v), you can update it's position in the priority queue in logarithmic time per adjacent node (with most implementations of a priority queue).
To name some specific data structures, the DecreaseKey(Q, v) function used below has logarithmic complexity for Fibonnaci heaps and pairing heaps (amortized).
More-concrete pseudocode for the algorithm
MstPrim(Graph* G)
for each u in G->vertices
u->visited = false
u->key = infinity
u->pi = NULL
Q = PriorityQueue(G->vertices)
while Q not empty
u = ExtractMin(Q)
u->visited = true
for each (v, w) in u->adjacent
if not v->visited and w < v->key
v->pi = u
v->key = w
DecreasedKey(Q, v) //O(log n)