Voici une question que j'ai récemment posée lors d'une interview. Un arbre binaire est donné avec une condition que chaque enfant gauche est 1 plus petit que la racine et que l'enfant droit est 1 plus grand. Voici un exemple d'arbre
Triez-le en O(1) et O(n) complexité du temps.
Voici les approches que j'ai suggérées:
Quelles sont vos approches?
Correction d'un nœud feuille de l'arbre en tant que NewHead.
Ecrire une fonction Pop () supprime un noeud de l’arbre donné ..!
Ecrivez un noeud pop de telle sorte que vous ne le retiriez que quand il le sera! égal à NewHead.
Pour extraire la valeur de l’arborescence, insérez-la dans l’arborescence Nouvelle recherche binaire avec le nœud Nouvelle tête comme tête.
Donc, vous allez supprimer un élément de l’arbre et l’ajouter à un nouvel arbre de recherche.
Jusqu'à ce que la tête de l'arbre pointe NewHead.
Donc, tous vos éléments sont maintenant dans l’arborescence de recherche binaire pointant vers la nouvelle tête, qui sera
évidemment dans l'ordre de tri.
Cela vous promet un tri dans O(NlogN).
Une analyse
Compte tenu de votre définition d'un arbre binaire, nous avons ce qui suit,
Chaque nœud a un parent, un enfant L et un enfant R .. où:
L < N
R > N
P > N
Nous pouvons aussi faire ceci:
L < N AND R > N => L < N < R => L < R
L < N AND P > N => L < N < P => L < P
R > N AND P > N => N < MIN(P,R)
N < MIN(P,R) AND L < N => L < N < MIN(P,R)
Et maintenant essayons de l’étendre, N.L = Left-child of N
:
N.L < N
N.R > N
N.P > N
N.L.L < N.L < MIN(N, N.L.R)
N.L.R > N.L > N.L.L
N.R.L < N.R < MIN(N, N.R.R)
N.R.R > N.R > N.R.L
IF N IS N.P LEFT-CHILD: N < N.P < MIN(N.P.P, N.P.R)
IF N IS N.P RIGHT-CHILD: N > N.P.R
Solution proposée
Ce problème semble complexe, mais ma solution utilisera le tri par fusion après l’insertion de valeurs dans un ordre de traversée gauche-droite-parent, ce qui aidera le tri à fusionner pour obtenir une complexité temporelle située entre son cas moyen et optimal, mais avec une astuce simple: les comparaisons que j'ai faites ci-dessus.
Nous collectons d’abord les nœuds d’arbres dans une liste, en utilisant la traversée Gauche-Droite-Parent, étant donné que: N.L < N < MIN(N.R, N.P)
et en donnant au parent un poids supérieur en supposant que O(N.R) <= O(N.P)
avec les valeurs décroît linéairement lorsque nous passons à gauche chaque fois .. > N.R.R > N.R > N > N.L > N.L.L > ..
.
Après avoir collecté les nœuds de l’arbre dans cet ordre de traversée, la liste contient des morceaux triés, ce qui facilitera le tri par fusion que nous utiliserons ensuite.
Cette solution fonctionne dans: Time = O(n log n + n)
, Space = O(n)
Voici l'algorithme écrit en Java (non testé) :
private class Node Comparable<Node>
{
public Node R;
public Node L;
public int value;
public Node (Node L, int val, Node R)
{
this.L = L;
this.value = val;
this.R = R;
}
@Override
public int compareTo(Node other)
{
return ((other != null) ? (this.value-other.value) : 0);
}
}
class Main
{
private static Node head;
private static void recursive_collect (Node n, ArrayList<Node> list)
{
if (n == null) return;
if (n.left != null) recursive_collect (n.L, list);
if (n.right != null) recursive_collect (n.R, list);
list.add(n.value);
}
public static ArrayList<Node> collect ()
{
ArrayList<Node> list = new ArrayList<Node>();
recursive_collect (head, list);
return list;
}
// sorting the tree: O(n log n + n)
public static ArrayList<Node> sortTree ()
{
// Collecting nodes: O(n)
ArrayList<Node> list = collect();
// Merge Sort: O(n log n)
Collections.sort(list);
return list;
}
// The example in the picture you provided
public static void createTestTree ()
{
Node left1 = new Node (new Node(null,-2,null), -1, new Node(null,0,null));
Node left2 = new Node (new Node(null,-1,null), 0, new Node(null,1,null));
Node right = new Node (left2, 1, new Node(null,2,null));
head = new Node (left1, 0, right);
}
// test
public static void main(String [] args)
{
createTestTree ();
ArrayList<Node> list = sortTree ();
for (Node n : list)
{
System.out.println(n.value);
}
}
}
Je suppose que vous recherchez DFS (recherche en profondeur d'abord). Dans le cadre de la recherche en profondeur d'abord, l'idée est de voyager aussi profondément que possible d'un voisin à l'autre avant de revenir en arrière. Ce qui détermine la profondeur possible, c'est que vous devez suivre les contours et que vous ne visitez aucun sommet.
boost le fournit déjà: voir ici
Utilisez le tri rapide.
Les nœuds sont triés au niveau le plus bas dans plusieurs tableaux et ces tableaux d'éléments triés sont fusionnés à la fin.
Par exemple.
Fonction quick_sort (noeud n)
1. Aller en mode gauche, si n'est pas null, appeler quick_sort dessus.
2. Aller aux éléments de droite, si n'est pas null, appeler quick_sort dessus.
3. Fusionner les résultats du tri du noeud gauche et du tri du noeud droit et du noeud actuel.
4. Renvoie le tableau fusionné.