With a TriTreeNode system you don't save positions only pointers to nodes that are neightbours and children. Then when doing the actual rendering you plot in the potitions.
If you need a higher detail you just divide the triangle. This needs only the first to coordinates to keep stored in a patch, so called topleft and bottomleft corner.
First I set up a big array of TriTreeNodes and keep track of how many are actually used. This saves creation of structs wich is time consuming and as it is used often the array is a member of the terrain class. The array is big but only stores pointers to other indices of the tritreenodes. Than I create an array for the patches wich holds the position and the opposite corner (x and z, y isn't needed here). Before rendering I call a recursive function to split the tritreenodes. In the rendering process I call a recursive function wich gets the two corners passed in. There you could use any calculation you desire.
When that's implemented the way I like it I will try to skip TriTreeNodes that will stay the same without recreating the whole tree.
Perlin Noise doesn't suite me I think as it won't save terrain changes. However it does have some attraction as (not sure here) you can 'zoom in at the detail'. With this TriTreeNode system you have a variation tree too - haven't dived into that yet - wich is a tree that will smooth heights for the details that hasn't been stored. That tree is being recreated when set dirty, it should be updated after modifying the terrain.
Creating a game is a game itself

EDIT:
Real-Time Dynamic Level of Detail Terrain Rendering with ROAM by Bryan Turner has three pages of explanation and a source that hits the core of this system.