二分搜索樹的遍歷和二叉樹的遍歷是一致的(二分搜索樹的實質本身就是一棵二叉樹),直接使用二叉樹的遍歷即可.
大一的時候數據結構學的還可以,感覺不是特別復雜
二叉樹的遍歷方式:
- 深度優先遍歷
1.前序遍歷
2.中序遍歷
3.后序遍歷
- 廣度優先遍歷
層序遍歷
前序遍歷
根節點->左孩子->右孩子
前序遍歷
遞歸實現
/**
* 對二叉樹進行前序遍歷
*/
public void preOrder(){
preOrder(root);
}
/**
* 前序遍歷的遞歸方式,深度優先
* 當前節點->左孩子->右孩子
* @param node 傳入的節點
*/
private void preOrder(Node node){
//遍歷到葉子節點時,退出當前的路線
if (node == null){
return;
}
//1.遍歷當前節點
System.out.print(node.data+"->");
//2.遍歷左孩子
preOrder(node.left);
//3.遍歷右孩子
preOrder(node.right);
}
非遞歸實現
/**
* 前序遍歷的非遞歸實現方式
*/
public void preOrderNr(){
//使用棧輔助實現前序遍歷
Stack<Node> stack = new Stack<>();
/*
前序遍歷的過程就是先訪問當前節點,然后再訪問左子樹,然后再右子樹
使用棧實現的時候,可以先將當前的節點入棧
當前節點出站的時候,分別將右孩子,左孩子入(棧的特點:先進后出)
*/
stack.push(root);
//棧不為空時
while (!stack.isEmpty()){
Node node = stack.pop();
//前序遍歷當前的節點
System.out.print(node.data + "->");
//先進后出
if (node.right != null){
stack.push(node.right);
}
if (node.left != null){
stack.push(node.left);
}
}
中序遍歷
左孩子->根節點->右孩子
中序遍歷
遞歸實現
/**
* 對中序遍歷進行中序遍歷
*/
public void midOrder(){
midOrder(root);
}
/**
* 中序遍歷的遞歸方式,深度優先
* 左孩子->當前節點->右孩子
* @param node 傳入的節點
*/
private void midOrder(Node node){
if (node == null){
return;
}
//1.中序遍歷左孩子
midOrder(node.left);
//2.遍歷根節點
System.out.print(node.data+"->");
//3.遍歷右孩子
midOrder(node.right);
}
非遞歸實現
/**
* 中序遍歷的非遞歸實現方式
*/
public void midOrderNr(){
//使用棧輔助實現前序遍歷
Stack<Node> stack = new Stack<>();
//輔助節點
Node p = root;
stack.add(p);
System.err.println();
//只要存在左孩子,就將左孩子入棧
while (!stack.isEmpty()){
if (p != null && p.left != null){
stack.add(p.left);
p = p.left;
}else {
p = stack.pop();
System.out.print(p.data+"->");
if (p != null && p.right != null){
//將右孩子入棧
stack.add(p.right);
p = p.right;
}else {
p = null;
}
}
}
后序遍歷
左孩子->右孩子->根節點
后序遍歷
遞歸實現
/**
* 二叉樹的后序遍歷
*/
public void afterOrder(){
afterOrder(root);
}
/**
* 左孩子->右孩子->父節點
* @param node 父節點
*/
private void afterOrder(Node node) {
if (node == null){
return;
}
afterOrder(node.left);
afterOrder(node.right);
System.out.print(node.data+"->");
}
非遞歸實現
/**
* 后序遍歷的非遞歸實現方式
*/
public void afterOrderNr(){
if (root != null){
Stack<Node> stack = new Stack<>();
stack.push(root);
Node p;
while (!stack.isEmpty()){
p = stack.peek();
if (p.left != null && root != p.left && root != p.right){
stack.push(p.left);
}else if (p.right != null && root!= p.right){
stack.push(p.right);
}else {
System.err.print(stack.pop().data+"->");
root = p;
}
}
}
}
層序遍歷
從左到右,從上到下
層序遍歷
/**
* 層序遍歷,從左到右,從上到下,一次遍歷
* 借助隊列實現
*/
public void levelOrder(){
Queue<Node> queue = new LinkedList<>();
/*
* 遍歷過程:
* 1. 首先根節點入隊
* 2. 每次出隊時, 都將當前節點的左右孩子先后入隊
* 3. 如果隊列為空的話, 則表示層序遍歷結束
* 5
* / \
* 3 6
* / \ \
* 2 4 8
* 針對上面的二分搜索樹, 詳細描述一下層序遍歷步驟
* 1. 5入隊, 隊列元素 : head->[5]<-tail
* 2. 5出隊, 5的左子樹3, 6入隊, 由于隊列是先入先出(FIFO), 所以先左后右, 隊列元素 : head->[3, 6]<-tail
* 3. 3出隊, 2, 4入隊, 隊列元素 : head->[6, 2, 4]<-tail
* 4. 6出隊, 左孩子為空,所以8入隊, 隊列元素 : head->[2, 4, 8]<-tail
* 5. 2,4,8依次出隊, 由于這三個節點都是葉子節點, 無子節點, 所以這三個節點出隊后隊列為空, 層序遍歷完成
* 6. 按照出隊的順序演示的遍歷結果為 : 5 3 6 2 4 8
*/
queue.add(root);
while (!queue.isEmpty()){
Node p = queue.poll();
System.err.print(p.data+"->");
if (p.left != null){
queue.add(p.left);
}
if (p.right != null){
queue.add(p.right);
}
}
小結:
相對來說非遞歸方式的效率會更高,但是遞歸方式實現邏輯更加清晰
參考博客:
https://blog.csdn.net/davidddl/article/details/75667092
https://blog.csdn.net/love905661433/article/details/82981527