平衡二叉樹筆記

1.二叉樹有幾種存儲方式,啥樣的二叉樹適合使用數組來存儲?

顯然只有數組和鏈表兩種方式,數組更適合於完全二叉樹,最典型的應用就是大小頂堆的使用,使用數組我們我們可以爲一組數在O(n)的時間內完成對一組數據的建堆操作。記住二叉樹的遞歸遍歷前中後序時間複雜度皆爲O(n).

2.既然有散列表(hash)爲什麼設計二叉樹

普通二叉查找樹(排序樹)不是太穩定,最差會達到O(N)而最好時大約爲O(logN),這顯然不符合我們在工程上的需求,故前輩們提出了性能穩定的平衡二叉樹,而其中又以紅黑樹的使用最爲廣泛,現在再來看hash與avl應該怎樣選擇,爲何avl更受歡迎?

  • 散列表無序存儲,假設要有序數據時必須先排序。
  • hash表闊容耗時多,而且當遇到散列衝突時,性能不穩,查找樹則不同。
  • 解決衝突及其耗時,雖然單個查找時間複雜度爲O(1),但是實際查找速度不一定有查找樹快
  • 散列表構造需要考慮太多因素,比如設計散列函數、衝突解決辦法等。
  • 若解決衝突方法不夠合理,裝填因子太大,會浪費太多空間
3.爲什麼要使用紅黑樹?avl不香嗎?

平衡二叉樹是爲了解決二叉查找樹在頻繁的動態更新中可能出現樹的高度遠遠大於logN的情況,從而導致各個操作的效率下降。而爲了解決這個問題,提出了平衡二叉樹,其中最具有代表性的就是紅黑樹,其實最早出現的是avl樹,不過儘管avl樹是一種高度平衡的二叉樹,查找的效率非常高,但是有利就有弊,它爲了維護這種高度的平衡就付出了更多的代價。每次插入刪除都要做調整,就比較複雜耗時,所以對於頻繁的插入刪除的數據集合,使用avl樹的代價有點高。而紅黑樹只是大概做到了近似平衡,並不是嚴格的平衡,所以在維護平衡的成本上,要比avl樹低。
紅黑樹的近似平衡體現在它從根節點到各個葉子節點的最長路徑,有可能會比最短路徑大一倍。

4.紅黑樹的定義
  • 根節點是黑色的
  • 每個葉子節點都是黑色的空節點,也就是說葉子節點不存儲數據
  • 任何相鄰的節點不能都是紅節點,即紅節點被黑色節點隔開
  • 每個節點到達其可達葉子節點的所有路徑都包含相同數目的黑色節點
5.怎樣實現一棵紅黑樹?

顯然當我們對紅黑樹進行插入和刪除時勢必會造成不滿足上面關於紅黑樹定義3、4點的要求,而如何建樹以及調整數是構成一顆二叉樹的基礎。

  • 紅黑樹規定,插入的節點必須是紅色的。而且,二叉查找樹中新插入的節點都是放在葉子節點上
  • 至於紅黑樹的葉子節點爲什麼設置爲黑色的空節點自然是爲了編程實現的簡便性,只有這樣纔可以將插入和刪除做成一個套路,不要強記,沒意義。瞭解節點的左右旋轉。
6.跳錶

調錶是一種各方面性能都比較優秀的動態數據結構,它基於鏈表實現,通過添加多級索引的方式設計,每一級索引以下一級的兩個或者更多節點爲間隔提取爲一個節點設計索引層,層層遞進,效率將非常高。

  • 仔細分析跳錶的數據結構會發現它的時間複雜度爲O(logN),和二分查找的時間複雜度相等。
  • 跳錶以空間換時間,那麼其是不是真的浪費內存哩?
  • 雖然空間複雜度爲O(N)的,但是在實際的軟件開發中每一個節點其實保存的是非常複雜的結構,而索引只是一個指針,所以完全不需要擔心浪費內存的問題。
  • 跳錶這個動態數據結構,不僅支持查找操作,還支持動態的插入、刪除操作,而且插入、刪除操作的時間複雜度也是 O(logn)。
  • 當不停地往跳錶中插入數據時,如果不更新索引,就有可能出現某 2 個索引結點之間數據非常多的情況。極端情況下,跳錶還會退化成單鏈表。所以需要某種手段來維護索引與原始鏈表大小之間的平衡,也就是說,如果鏈表中結點多了,索引結點就相應地增加一些,避免複雜度退化,以及查找、插入、刪除操作性能下降。如何做哩?
  • 跳錶是通過隨機函數來維護前面提到的“平衡性”。
7.Linux常用命令

(1) grep: global search regular expression(RE) and print out the line
示例:grep "skip_atoi(" vsprintf.c

-E 將範本樣式爲延伸的普通表示法來使用,意味着使用能使用擴展正則表達式。
-i 忽略字符大小寫的差別。
-R/-r 此參數的效果和指定“-d recurse”參數相同。
-v 反轉查找。
-o 只輸出文件中匹配到的部分。

(2)find: 用來在指定目錄下查找文件
syntax:find(選項)(參數)
任何位於參數之前的字符串都將被視爲欲查找的目錄名。如果使用該命令時,不設置任何參數,則find命令將在當前目錄下查找子目錄與文件。並且將查找到的子目錄和文件全部進行顯示。

-name<範本樣式>:指定字符串作爲尋找文件或目錄的範本樣式;
-iname<範本樣式>:此參數的效果和指定“-name”參數類似,但忽略字符大小寫的差別;
-ls:假設find指令的回傳值爲Ture,就將文件或目錄名稱列出到標準輸出;
-path<範本樣式>:指定字符串作爲尋找目錄的範本樣式;
-regex<範本樣式>:指定字符串作爲尋找文件或目錄的範本樣式;

find .  #列出當前目錄及子目錄下所有文件和文件夾
find /home -name "*.txt"    #在/home目錄下查找以.txt結尾的文件名
find /home -iname "*.txt"   #同上,但忽略大小寫
find . \( -name "*.txt" -o -name "*.pdf" \)#當前目錄及子目錄下查找所有以.txt和.pdf結尾的文件
find /usr/ -path "*local*"  #匹配文件路徑或者文件
find . -regex ".*\(\.txt\|\.pdf\)$"#基於正則表達式匹配文件路徑
find /home ! -name "*.txt"  #找出/home下不是以.txt結尾的文件
find . -type 類型參數   #根據文件類型進行搜索

(3)xargs: 給其他命令傳遞參數的一個過濾器
是給其他命令傳遞參數的一個過濾器,也是組合多個命令的一個工具。它擅長將標準輸入數據轉換成命令行參數,xargs能夠處理管道或者stdin並將其轉換成特定命令的命令參數。xargs也可以將單行或多行文本輸入轉換爲其他格式,例如多行變單行,單行變多行。

#假設有文件cat test.txt
a b c d e f g
h i j k l m n
o p q
r s t
u v w x y z
1、cat test.txt | xargs    #多行輸入單行輸出
輸出:a b c d e f g h i j k l m n o p q r s t u v w x y z
2、cat test.txt | xargs -n3#-n選項多行輸出如下
輸出:a b c
    d e f
    g h i
    j k l
    m n o
    p q r
    s t u
    v w x
    y z
3、echo "nameXnameXnameXname" | xargs -dX   #-d選項可以自定義一個定界符
輸出:name name name name
4、echo "nameXnameXnameXname" | xargs -dX -n2   #結合-n選項使用
輸出:  name name
        name name
5、cat test.txt |xargs -I {} echo "-p {} -l" #讀取stdin,將格式化後的參數傳遞給命令
輸出:  -p b c d e f g -l
        -p h i j k l m n -l
        -p o p q -l
        -p r s t -l
        -p u v w x y z -l
6、find . -type f -name "*.log" -print0 | xargs -0 rm -f    #xargs結合find使用
    #用rm 刪除太多的文件時候,可能得到一個錯誤信息:/bin/rm Argument list too long.
    #用xargs去避免這個問題
7、find . -type f -name "*.php" -print0 | xargs -0 wc -l
    #統計一個源代碼目錄中所有php文件的行數
    #xargs -0將\0作爲定界符。

(4)tar: 爲linux的文件和目錄創建檔案
利用tar命令,可以把一大堆的文件和目錄全部打包成一個文件,這對於備份文件或將幾個文件組合成爲一個文件以便於網絡傳輸是非常有用的。注意區分打包和壓縮,打包是指將一大堆文件或目錄變成一個總的文件;壓縮則是將一個大的文件通過一些壓縮算法變成一個小文件。區分這兩個概念源於Linux中很多壓縮程序只能針對一個文件進行壓縮,這樣當你想要壓縮一大堆文件時,你得先將這一大堆文件先打成一個包(tar命令),然後再用壓縮程序進行壓縮(gzip bzip2命令)。
syntax:tar(選項)(參數)

-c或–create:建立新的備份文件;
-x或–extract或–get:從備份文件中還原文件;
-v:顯示操作過程;
-f<備份文件>或–file=<備份文件>:指定備份文件;
-j:支持bzip2解壓文件;
-z或–gzip或–ungzip:通過gzip指令處理備份文件;
-t或–list:列出備份文件的內容;

示例程序:

tar -cvf log.tar log2012.log        #僅打包,不壓縮! 
tar -zcvf log.tar.gz log2012.log    #打包後,以 gzip 壓縮 
tar -jcvf log.tar.bz2 log2012.log   #打包後,以 bzip2 壓縮 
tar -ztvf log.tar.gz                #查閱上述tar包內有哪些文件
tar -zxvf /opt/soft/test/log.tar.gz #將tar包解壓縮

想要最簡單的使用tar只需要記得下面的幾個公式就可以了 :
壓 縮:tar -jcv -f filename.tar.bz2 要被壓縮的文件或目錄名稱
查 詢:tar -jtv -f filename.tar.bz2
解壓縮:tar -jxv -f filename.tar.bz2 -C 欲解壓縮的目錄

發佈了39 篇原創文章 · 獲贊 7 · 訪問量 4392
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章