There seem to be edge case bugs when the data is empty or consists of only one character repeated ("aaaaaaa..."). I haven't run the code though. A good way to avoid making such bugs is to write more unit tests, because then your mind goes into a state where it actively looks for corner cases. The end result is more robust code all around.
Other small things you might want to consider is being more consistent with the types. E.g you are using int and unsigned int in places where size_t probably would be better. Using unsigned short for the frequencies array will cause bugs on specially crafted input data.
I think you also should consider what your goal is. If it is speed, then you would develop your code on way, if it is memory efficiency another and, if it is readability of the source code a third.