Comments 2
Вам стоит дать определение "двоичного дерева поиска" в самом начале. Потому что все ваши следующие определения, вроде сбалансированности, хоть и технически применимы ко всем деревьям, на практике используются только в деревьях поиска. Потому что именно упорядоченность ключей позволяет делать всякие операции за один спуск по дереву, из-за чего высота дерева начинает играть роль.
Далее, временная сложность O(log n) получается только у сбалансированных деревьев. Ибо это свойство гарантирует примерно уменьшение дерева в 2 раза на каждой развилке.
Ваши операции добавления/удаления не балансируют дерево, поэтому вся ваша структура работает за O(n) в худшем случае. Если я вызову операцию добавления с увеличивающимеся числами, то вы пострите "палку", где у всех вершин нет левого ребенка, но почти у всех есть только правый ребенок.
Балансированные деревья поиска немного более сложные структуры данных, вроде AVL-, красно-черных- или декартовых деревьев.
Бинарное дерево поиска в Swift