1. 程式人生 > 實用技巧 >Django學習日記-06新url多對多表新增 編輯操作

Django學習日記-06新url多對多表新增 編輯操作

目錄

二叉樹

二叉樹是一種非常重要的資料結構,非常多其他資料結構都是基於二叉樹的基礎演變而來的。對於二叉樹,有深度遍歷和廣度遍歷,深度遍歷有前序、中序以及後序三種遍歷方法,廣度遍歷即我們尋常所說的層次遍歷。由於樹的定義本身就是遞迴定義,因此採用遞迴的方法去實現樹的三種遍歷不僅easy理解並且程式碼非常簡潔,而對於廣度遍歷來說,須要其他資料結構的支撐。比方堆了。所以。對於一段程式碼來說,可讀性有時候要比程式碼本身的效率要重要的多。

遍歷路徑

前序遍歷:根->左->右

中序遍歷:左->根->右(最重要)

後續遍歷:左->右->根

層次遍歷:根->左->右

樹遍歷框架

所有樹的遍歷均可以套用樹遍歷框架

void traverse(TreeNode root) {
    // 前序遍歷
    traverse(root.left)
    // 中序遍歷
    traverse(root.right)
    // 後序遍歷
}

例子1(二叉搜尋樹轉換為單向連結串列)

二叉樹資料結構TreeNode可用來表示單向連結串列(其中left置空,right為下一個連結串列節點)。實現一個方法,把二叉搜尋樹轉換為單向連結串列,要求值的順序保持不變,轉換操作應是原址的,也就是在原始的二叉搜尋樹上直接修改。

返回轉換後的單向連結串列的頭節點。

示例:

輸入: [4,2,5,1,3,null,6,0]
輸出: [0,null,1,null,2,null,3,null,4,null,5,null,6]
    //上級節點
	TreeNode preNode;
    //頭節點
    TreeNode headNode;
    public TreeNode convertBiNode(TreeNode root) {
        if (root == null) {
            return null;
        }
        search(root);
        return headNode;
    }

    /**
     * 中序遍歷框架
     * search(node.left)
     * do current value
     * search(node.right)
     * @param node
     */
    public void search(TreeNode node) {
        if (node == null) {
            return;
        }
        //1.遍歷左節點
        search(node.left);

        //2.處理當前節點
        if (preNode != null) {
            //當前節點設定為上個節點的右節點
            preNode.right = node;
        } else {
            headNode = node;
        }
        //當前節點的左節點設定為null
        node.left = null;
        preNode = node;
        //3.遍歷右節點
        search(node.right);
    }

例子2(刪除二叉搜尋樹中的 key 對應的節點)

給定一個二叉搜尋樹的根節點 root 和一個值 key,刪除二叉搜尋樹中的 key 對應的節點,並保證二叉搜尋樹的性質不變。返回二叉搜尋樹(有可能被更新)的根節點的引用。

一般來說,刪除節點可分為兩個步驟:

首先找到需要刪除的節點;
如果找到了,刪除它。
說明: 要求演算法時間複雜度為 O(h),h 為樹的高度。

分析:

  1. 當前節點沒有左子節點

    返回root.right

  2. 當前節點沒有右子節點

    返回root.left

  3. 當前節點既有左子節點和右子節點時

    1. 找到右子節點下面最後一個左子結點

    2. 將root的左子節點放到右子節點下面最後一個左子結點的左子節點上

    3. 直接返回右子節點

BTS數遍歷框架

二叉搜尋樹(Binary Search Tree,簡稱 BST)是一種很常用的的二叉樹。它的定義是:

一個二叉樹中,任意節點的值要大於等於左子樹所有節點的值,且要小於等於右邊子樹的所有節點的值

void BST(TreeNode root, int target) {
    if (root.val == target)
        // 找到目標,做點什麼
    if (root.val < target) 
        //目標比節點值大,目標肯定在右節點
        BST(root.right, target);
    if (root.val > target)
        //目標比節點值小,目標肯定在左節點
        BST(root.left, target);
}
public TreeNode deleteNode(TreeNode root, int key) {
    if(root == null) {
        return null;
    }
    if(root.val == key){
        if(root.right == null){
            return root.left;
        }
        if(root.left == null) {
            return root.right;
        }
        //當目標節點左右子節點都存在時
        TreeNode node = root.right;
        //找到右子節點下面最後一個左子結點
        while(node.left != null){
            node = node.left;
        }
        //將root的左子節點放到右子節點下面最後一個左子結點的左子節點上
        node.left = root.left;
        //直接返回右子節點
        return root.right;
    }else if(key < root.val){
        root.left = deleteNode(root.left,key);
    }else{
        root.right = deleteNode(root.right,key);
    }
    return root;
}

例子3(根據前序中序遍歷結果重建二叉樹)

//根據前序中序遍歷結果重建二叉樹框架
//pre 前序
//mid 中序
TreeNode buildNode(List<Integer> pre,List<Integer> mid){
    if(pre.size() == 0){
        return null;
    }
    //前序第一個值肯定是根節點
    TreeNode root = new TreeNode(pre.get(0));
    //中序對應值的索引作為左右子樹分割點
    int i = mid.indexOf(pre.get(0));
    //重建左樹
    root.left = buildNode(pre.subList(1,i+1),mid.subList(0,i));
    //重建右樹
    root.right = buildNode(pre.subList(i+1,pre.size()),mid.subList(i+1,mid.size()));
    return root;
}

java程式碼

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
   
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        List<Integer> mid=new ArrayList<>();
        List<Integer> pre=new ArrayList<>();
        for(int i=0;i<preorder.length;i++){
           pre.add(preorder[i]);
           mid.add(inorder[i]);
        }
        return buildNode(pre,mid);
    }
    /**
    *pre 前序
    *mid 中序
    */
    TreeNode buildNode(List<Integer> pre,List<Integer> mid){
        if(pre.size() == 0){
            //1.遞迴停止條件
            return null;
        }
        //2.前序第一個是root節點
        TreeNode root = new TreeNode(pre.get(0));
        //3.找到中序中root節點的索引
        //中序遍歷的順序是左->根->右,所以root節點的索引左邊一定是左子節點,右邊一定是右子節點,
        //這樣就就分成左右兩部分了
        int i = mid.indexOf(pre.get(0));

        //這樣就處理完畢了,接下來就遞迴重複上面步驟了
        //遞迴處理左節點資料,前序1->i+1,中序:0->i
        root.left = buildNode(pre.subList(1,i+1),mid.subList(0,i));
        //遞迴處理右節點資料,前序i+1->end,中序:i+1->end
        root.right = buildNode(pre.subList(i+1,pre.size()),mid.subList(i+1,mid.size()));
        return root;
    }