MPI provides PVM-like calls
MPI_Unpack. These can be used to pack data from
a data type with a complex layout into a contiguous buffer
before sending. On receiving, the data can be unpacked
and placed again into a new complex layout.
These two functions are provided largely for backward compatibility with older PVM codes. But they can be also used for more elaborate situations, for example, when a message is received in several chunks and the way that later chunks are going to be interpreted may depend on what's in the earlier ones.
Because the memory lay-out of the data type from which data is plucked for sending needs to be known in advance packing is unlikely to be of much use in transmitting lists, trees, and graphs, unless the latter live within the user-defined arrays and appropriate maps are available.
So how would you send a tree or a graph across? You would have to traverse it, extract all the data, copy it onto a contiguous buffer, provide a prescription for reconstruction of the tree on the other side, and then transmit both types of the information.
But sometimes people implement trees and linked lists themselves within finite size arrays, e.g., arrays of pairs or arrays of triples - if this is the case, then the whole array can be transmitted remembering, of course, about defining array entries for MPI as appropriate datatypes.