iOS話題:算法-排序炼列、二叉樹-2020-05-13

排序

排序是iOS算法中提及最多的話題俭尖,比較有名的有八大排序算法。

image.png

數(shù)據(jù)結(jié)構(gòu)常見的八大排序算法(詳細(xì)整理)

八大排序算法

iOS排序算法

七種常見的數(shù)組排序算法整理(C語言版本)

1.快速排序

這個(gè)是曝光率最高的排序算法,基本思想:挖坑填數(shù)+分治法

  • 從序列當(dāng)中選擇一個(gè)基準(zhǔn)數(shù)(pivot)熊赖,在這里我們選擇序列當(dāng)中第一個(gè)數(shù)最為基準(zhǔn)數(shù)陷猫;

  • 將序列當(dāng)中的所有數(shù)依次遍歷绣檬,比基準(zhǔn)數(shù)大的位于其右側(cè),比基準(zhǔn)數(shù)小的位于其左側(cè)墨缘;

  • 遞歸镊讼,左右兩邊分別進(jìn)行以上步驟平夜;退出條件:未排序序列長(zhǎng)度為0忽妒;

  • 快速排序的Object-C代碼如下:

- (void)quickSort:(NSMutableArray *)mutableArray start:(NSInteger)start end:(NSInteger)end {
    // 遞歸函數(shù)退出條件:只有1個(gè)元素或者沒有元素
    if (start >= end) {
        return;
    }
    
    // 取第一個(gè)元素為基準(zhǔn)元素
    id pivot = mutableArray[start];
    
    // 設(shè)置可以移動(dòng)的下標(biāo)
    NSInteger i = start;
    NSInteger j = end;
    
    // 不斷重復(fù),將小于基準(zhǔn)pivot的移到左邊吃溅;將大于基準(zhǔn)pivot的移到右邊决侈;形成兩個(gè)子數(shù)組赖歌;
    while (i < j) {
        // 從右開始向左尋找第一個(gè)小于pivot的值;(對(duì)于本來就大于或者等于基準(zhǔn)的數(shù)讯蒲,保持不動(dòng))
        while ((i < j) && ([mutableArray[j] hash] >= [pivot hash])) {
            j--;
        }
        // 將小于pivot的值移到左邊;填坑mutableArray[I]
        if (i < j) {
            mutableArray[i] = mutableArray[j];
        }
        
        // 從左開始向右尋找第一個(gè)大于pivot的值;(對(duì)于本來就小于或者等于基準(zhǔn)的數(shù)墨林,保持不動(dòng))
        while ((i < j) && ([mutableArray[i] hash] <= [pivot hash])) {
            I++;
        }
        // 將大于pivot的值移到右邊; 填坑mutableArray[j]犯祠;(mutableArray[j]上一步已經(jīng)移到左邊衡载,現(xiàn)在已經(jīng)是坑了)
        if (i < j) {
            mutableArray[j] = mutableArray[I];
        }
    }
    // 循環(huán)結(jié)束后痰娱,說明 i==j,此時(shí)左邊的值全都小于pivot,右邊的值全都大于pivot
    // 將一開始就挖出的基準(zhǔn)pivot放回兩個(gè)子數(shù)組的中間位置
    mutableArray[i] = pivot;    // 這個(gè)時(shí)候i == j鲸睛;用mutableArray[j] = pivot;也是可以的
    
    // 遞歸官辈,對(duì)左右兩個(gè)子數(shù)組繼續(xù)進(jìn)行“挖坑填數(shù)”操作; 這個(gè)時(shí)候i==j遍坟; i或者j的位置是基準(zhǔn)數(shù)愿伴,已經(jīng)排好,不需要再參加排序
    // 左側(cè)序列繼續(xù)排序
    [self quickSort:mutableArray start:start end:(i-1)];
    // 右側(cè)序列繼續(xù)排序
    [self quickSort:mutableArray start:(j+1) end:end];
}

由于iOS中數(shù)組成員是對(duì)象鹅经,所以取hash值進(jìn)行比較瞬雹。注意:對(duì)象不能直接用"<酗捌、 =涌哲、 >"等進(jìn)行比較阀圾,否則可能會(huì)出現(xiàn)@88 > @89的情況。實(shí)際試驗(yàn)涡真,對(duì)于NSStringNSNumber哆料,采用hash值比較东亦,效果很不錯(cuò)唬渗。

  • 封裝:實(shí)現(xiàn)算法的時(shí)候镊逝,以可變數(shù)組為參數(shù),排序之后他巨,可變數(shù)組參數(shù)內(nèi)容被改變染突。在實(shí)際使用中辈灼,改變傳入?yún)?shù)內(nèi)容的做法很不好巡莹。所以封裝一層,不改變使用者給的參數(shù)囚霸,將排序結(jié)果激才,以一個(gè)新數(shù)組的形式返回瘸恼,保持“純函數(shù)”的特性东帅。
/**
 排序算法名稱
 */
typedef NS_ENUM(NSInteger,SortType) {
    // 快速排序
    SortTypeQuick = 1,
};

// 統(tǒng)一封裝,以返回值的形式給出排序結(jié)果帐我,不改變用戶給出的參數(shù)焚刚,保持“純函數(shù)”特性
- (nullable NSArray *)sort:(nullable NSArray *)array type:(SortType)type {
    // 參數(shù)檢查
    if ((array == nil) || (array.count <= 1)) {
        return nil;
    }
    
    // 使用可變數(shù)組進(jìn)行操作矿咕,不改變輸入?yún)?shù)
    NSMutableArray *tempArray = [NSMutableArray arrayWithArray:array];
    
    // 根據(jù)SortType參數(shù)選擇不同的排序算法
    switch (type) {
        case SortTypeQuick:
            [self quickSort:tempArray start:0 end:(tempArray.count-1)];
            break;
            
        default:
            break;
    }
    
    // 返回排序后的數(shù)組
    return [tempArray copy];
}
  • 測(cè)試:可以用一個(gè)數(shù)字和字符的混合數(shù)組進(jìn)行測(cè)試:
//
//
// 統(tǒng)一的測(cè)試代碼
//
//
- (void)sortTest:(SortType)type {
    NSArray *arrayBeforeSort = [NSMutableArray arrayWithObjects:@89,@"hello",@22,@95,@"Hello",@66,@22,@"world",@57, nil];
    NSLog(@"快速排序之前:%@", arrayBeforeSort);
    NSArray *arrayAfterSort = [self sort:arrayBeforeSort type:type];
    NSLog(@"快速排序之后:%@", arrayAfterSort);
}
企業(yè)微信截圖_d4a70aab-e5ef-4bed-ad68-cabf71fbd223.png

2. 冒泡排序

  • 將序列當(dāng)中的左右元素碳柱,依次比較莲镣,保證右邊的元素始終大于左邊的元素瑞侮;
    ( 第一輪結(jié)束后鼓拧,序列最后一個(gè)元素一定是當(dāng)前序列的最大值季俩;)
  • 對(duì)序列當(dāng)中剩下的n-1個(gè)元素再次執(zhí)行步驟1。
  • 對(duì)于長(zhǎng)度為n的序列店归,一共需要執(zhí)行n-1輪比較
- (void)bubbleSort:(NSMutableArray *)mutableArray {
    // 執(zhí)行n-1輪消痛,最后一個(gè)元素不需要比較
    for (NSInteger i = 0; i < (mutableArray.count - 1); i++) {
        for (NSInteger j = 0; j < (mutableArray.count - i - 1); j++) {
            // 如果比旁邊的元素大秩伞,就交互
            if ([mutableArray[j] hash] > [mutableArray[j+1] hash]) {
                id temp = mutableArray[j];
                mutableArray[j] = mutableArray[j+1];
                mutableArray[j+1] = temp;
            }
        }
    }
}

3. 選擇排序

  • 從當(dāng)前序列選出最小的元素稠歉,排在第1位汇陆;

  • 從余下的n-1個(gè)元素中選出最小值毡代,排在第2位教寂;

  • .... 進(jìn)行n-1輪酪耕,就排好了。

- (void)selectSort:(NSMutableArray *)mutableArray {
    // 執(zhí)行n-1輪看尼,最后一個(gè)元素不需要比較
    for (NSInteger i = 0; i < (mutableArray.count - 1); i++) {
        // 最小值默認(rèn)是本輪第1個(gè)
        NSInteger minIndex = I;
        
        // 將余下的逐個(gè)比較藏斩,記下最小值的下標(biāo)
        for (NSInteger j = i; j < mutableArray.count; j++) {
            if ([mutableArray[j] hash] < [mutableArray[minIndex] hash]) {
                minIndex = j;
            }
        }
        // 將最小值和當(dāng)前位置交換
        if (minIndex != i) {
            id temp = mutableArray[I];
            mutableArray[i] = mutableArray[minIndex];
            mutableArray[minIndex] = temp;
        }
    }
}

4. 堆排序

  • 首先將序列構(gòu)建稱為"大頂堆"狰域;
    (這樣滿足了大頂堆那條性質(zhì):位于根節(jié)點(diǎn)的元素一定是當(dāng)前序列的最大值)
image.png
  • 取出當(dāng)前大頂堆的根節(jié)點(diǎn)兆览,將其與序列末尾元素進(jìn)行交換拓颓;
    (此時(shí):序列末尾的元素為已排序的最大值驶睦;由于交換了元素,當(dāng)前位于根節(jié)點(diǎn)的堆并不一定滿足大頂堆的性質(zhì))
image.png

交換后,排好了一個(gè)元素溉痢,但是堆被破壞了孩饼。接下來仍然需要先創(chuàng)建“大頂堆”镀娶,然后交換

  • .... 繼續(xù)重復(fù)n-1次梯码,全部排好。
// 大頂堆調(diào)整
- (void)maxHeapAdjust:(NSMutableArray *)mutableArray start:(NSInteger)start end:(NSInteger)end {
    // 建立父節(jié)點(diǎn)指標(biāo)和子節(jié)點(diǎn)下標(biāo)
    NSInteger dadIndex = start;
    NSInteger sonIndex = 2 * dadIndex + 1;
    
    // 在范圍內(nèi)儿奶,進(jìn)行比較和交互闯捎,保證父節(jié)點(diǎn)比兩個(gè)子節(jié)點(diǎn)都大
    while (sonIndex <= end) {
        // 兩個(gè)子節(jié)點(diǎn)比較隙券,取大的那個(gè)
        if (((sonIndex + 1) <= end) && ([mutableArray[sonIndex + 1] hash] > [mutableArray[sonIndex] hash])) {
            sonIndex++;
        }
        
        // 父節(jié)點(diǎn)大于子節(jié)點(diǎn)娱仔,調(diào)整完成
        if ([mutableArray[dadIndex] hash] > [mutableArray[sonIndex] hash]) {
            return;
        } else {
            // 父節(jié)點(diǎn)小于子節(jié)點(diǎn)游桩,交互兩個(gè)值
            id temp = mutableArray[dadIndex];
            mutableArray[dadIndex] = mutableArray[sonIndex];
            mutableArray[sonIndex] = temp;
            // 父節(jié)點(diǎn)較小借卧,和子節(jié)點(diǎn)交互完畢后铐刘,繼續(xù)與孫子節(jié)點(diǎn)比較
            dadIndex = sonIndex;
            sonIndex = 2 * dadIndex + 1;
        }
    }
}

// 堆排序
- (void)heapSort:(NSMutableArray *)mutableArray {
    // 初始化,創(chuàng)建大頂推挂签;
    // 最后一個(gè)有孩子的節(jié)點(diǎn)的位置 i =  (length -1) / 2
    for (NSInteger i = (mutableArray.count - 1) / 2; i >= 0; i--) {
        [self maxHeapAdjust:mutableArray start:i end:(mutableArray.count - 1)];
    }
    
    // 重復(fù)n次饵婆; 1.把根節(jié)點(diǎn)(第一個(gè)元素戏售,也就是最大的元素)和當(dāng)前排列的元素交換灌灾,排好一個(gè)锋喜;2跑芳,將剩余的元素調(diào)整為大頂推
    for (NSInteger j = (mutableArray.count - 1); j > 0; j--) {
        // 交換根節(jié)點(diǎn)直颅,也就是0號(hào)元素和當(dāng)前位置
        id temp = mutableArray[0];
        mutableArray[0] = mutableArray[j];
        mutableArray[j] = temp;
        // 調(diào)整剩余的元素為大頂堆
        [self maxHeapAdjust:mutableArray start:0 end:(j-1)];
    }
}

5. 插入排序

插入排序的基本思想是:每步將一個(gè)待排序的記錄功偿,按其關(guān)鍵碼值的大小插入前面已經(jīng)排序的文件中適當(dāng)位置上械荷,直到全部插入完為止

// 插入排序
- (void)insertSort:(NSMutableArray *)mutableArray {
    // 遍歷數(shù)組中的所有元素吨瞎,其中0號(hào)索引元素默認(rèn)已排序颤诀,因此從1開始
    for (NSInteger i = 1; i < mutableArray.count; i++) {
        // 要找插入位置,前面已經(jīng)排好的序列要往后面挪一個(gè)位置遗淳,所以要先把當(dāng)前的待插入元素先保存起來
        id temp = mutableArray[I];
        // 從已經(jīng)排好的序列尾部往前找屈暗,第一個(gè)數(shù)也要參與比較
        for (NSInteger j = i; j > 0; j--) {
            if ([mutableArray[j-1] hash] > [temp hash]) {
                // 前面的元素比現(xiàn)在的大养叛,就往后挪一格一铅;
                mutableArray[j] = mutableArray[j-1];
                // 如果第0號(hào)元素都比當(dāng)前元素大,那么當(dāng)前元素要插入第0號(hào)位置
                if ((j-1) == 0) {
                    mutableArray[0] = temp;
                    break;
                }
            } else {
                // 后面的元素比當(dāng)前的大,就說明找到位置了戈擒,插入艰毒,完成此輪排序
                mutableArray[j] = temp;
                break;
            }
        }
    }
}

未完待續(xù).....

希爾排序丑瞧,歸并排序绊汹,基數(shù)排序這三種西乖,看了參考文章获雕,不是很理解,暫時(shí)就不實(shí)踐了庵楷。

二叉搜索樹

  • 樹: 每個(gè)結(jié)點(diǎn)有零個(gè)或多個(gè)子結(jié)點(diǎn)嫁乘;沒有父結(jié)點(diǎn)的結(jié)點(diǎn)稱為根結(jié)點(diǎn)蜓斧;每一個(gè)非根結(jié)點(diǎn)有且只有一個(gè)父結(jié)點(diǎn)挎春;

  • 二叉樹: 是每個(gè)結(jié)點(diǎn)最多有兩個(gè)子樹的樹結(jié)構(gòu)直奋。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)脚线。
    一棵深度為k邮绿,且有2^k-1個(gè)節(jié)點(diǎn)的二叉樹,稱為滿二叉樹顾腊。這種樹的特點(diǎn)是每一層上的節(jié)點(diǎn)數(shù)都是最大節(jié)點(diǎn)數(shù)杂靶。
    在一棵二叉樹中吗垮,除最后一層外烁登,若其余層都是滿的防泵,并且最后一層或者是滿的,或者是在右邊缺少連續(xù)若干節(jié)點(diǎn)寿谴,則此二叉樹為完全二叉樹讶泰。

  • 二叉查找樹(Binary Search Tree)拂到,(又:二叉搜索樹兄旬,二叉排序樹: 它或者是一棵空樹,或者是具有下列性質(zhì)的二叉樹:

  1. 若它的左子樹不空宋舷,則左子樹上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值祝蝠,(大頂堆)绎狭;
  2. 若它的右子樹不空坟岔,則右子樹上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值摔桦,(小頂堆)邻耕;
  3. 它的左鸥咖、右子樹也分別為二叉排序樹。
  4. 沒有鍵值相等的節(jié)點(diǎn)兄世。
  • 二叉樹遍歷:以跟為參考來說啼辣。前序:根-》左-》右;中序:左-》根-》右御滩;后序:左-》右-》根

  • 二叉樹算法主要是遞歸的思想

【iOS】二叉樹的各種問題(OC代碼)

二叉搜索樹的Model

對(duì)于二叉搜索樹這種數(shù)據(jù)類型鸥拧,用簡(jiǎn)單的數(shù)組來表示是不適合的。所以要建立一個(gè)模型:

  • 值: 就用最簡(jiǎn)單的整數(shù)來表示削解,實(shí)際使用中,這個(gè)整型值也是必不可少的氛驮,可以單做key來用腕柜,這是二叉搜索樹排序的憑證。

  • 左子樹: 用一個(gè)同類型的指針表示

  • 右子樹: 用一個(gè)同類型的指針表示

以上3個(gè)是二叉搜索樹必不可少的屬性矫废,

@interface BinaryTreeNode : NSObject

// 值盏缤;當(dāng)做key來用,是排序用的憑證
@property (assign, nonatomic) NSInteger value;

// 左子樹
@property (strong, nonatomic) BinaryTreeNode *leftChild;

// 右子樹
@property (strong, nonatomic) BinaryTreeNode *rightChild;

// ... 添加其他需要的屬性成員

@end

添加節(jié)點(diǎn)

  • 與鏈表類似蓖扑,一個(gè)根節(jié)點(diǎn)*rootNode就代表一棵樹唉铜。要添加節(jié)點(diǎn),就要從這個(gè)根節(jié)點(diǎn)*rootNode開始律杠。

  • 采用“遞歸”的思想潭流,就很簡(jiǎn)單:如果節(jié)點(diǎn)還不存在柿赊,那么就新建節(jié)點(diǎn),添加完成幻枉,這也是“遞歸”的退出條件碰声。如果值偏小,那么就去“左子樹”熬甫;如果值偏大胰挑,那么就去“右子樹”;如果值相等椿肩,就忽略瞻颂。

  • 到了“左子樹”或者“右子樹”,重復(fù)上面的過程就可以了郑象。這就是“遞歸”贡这。

  • 最后,返回根節(jié)點(diǎn)*rootNode厂榛,這代表了一棵樹盖矫。

/**
 *  向二叉排序樹節(jié)點(diǎn)添加一個(gè)節(jié)點(diǎn)
 *
 *  @param rootNode 根節(jié)點(diǎn)
 *  @param value    值
 *
 *  @return 根節(jié)點(diǎn)
 */
+ (BinaryTreeNode *)addNode:(BinaryTreeNode *)rootNode value:(NSInteger)value {
    // 根節(jié)點(diǎn)不存在,創(chuàng)建節(jié)點(diǎn)
    if (rootNode == nil) {
        rootNode = [[BinaryTreeNode alloc] init];
        rootNode.value = value;
        NSLog(@"node:%@", @(value));
    } else if (value < rootNode.value) {
        NSLog(@"to left");
        // 值小于根節(jié)點(diǎn)击奶,則插入到左子樹辈双;這是遞歸,左子樹將做同樣的事
        rootNode.leftChild = [BinaryTree addNode:rootNode.leftChild value:value];
    } else if (value > rootNode.value) {
        NSLog(@"to right");
        // 值大于根節(jié)點(diǎn)柜砾,則插入到右子樹湃望;這是遞歸,右子樹將做同樣的事
        rootNode.rightChild = [BinaryTree addNode:rootNode.rightChild value:value];
    } else {
        NSLog(@"二叉排序樹沒有鍵值相等的節(jié)點(diǎn)痰驱,值%@已存在证芭,不能插入", @(value));
    }
    return rootNode;
}

創(chuàng)建二叉搜索樹

反復(fù)調(diào)用添加節(jié)點(diǎn)方法就可了。

/**
 *  創(chuàng)建二叉排序樹
 *  二叉排序樹:左節(jié)點(diǎn)值全部小于根節(jié)點(diǎn)值担映,右節(jié)點(diǎn)值全部大于根節(jié)點(diǎn)值
 *
 *  @param values 數(shù)組
 *
  *  @return 二叉樹根節(jié)點(diǎn)
 */
+ (BinaryTreeNode *)createTreeWithValues:(NSArray<NSNumber *> *)values {
    BinaryTreeNode *rootNode = nil;
    for (NSNumber *number in values) {
        NSInteger value = [number integerValue];
        rootNode = [BinaryTree addNode:rootNode value:value];
    }
    return rootNode;
}
  • 測(cè)試一下废士,新建一個(gè)Controller,用一個(gè)屬性持有這個(gè)二叉搜索樹另萤。
@interface TreeViewController ()

// 二叉搜索樹的根節(jié)點(diǎn)湃密,代表一棵樹
@property (strong, nonatomic) BinaryTreeNode *rootNode;

@end

輸入用一串值诅挑,得到一顆二叉搜索樹

// 創(chuàng)建樹
- (IBAction)createButtonTouched:(id)sender {
    NSArray *values = @[@200, @23, @456, @89, @23, @670, @5674, @15];
    self.rootNode = [BinaryTree createTreeWithValues:values];
}

用斷點(diǎn)四敞,查看“鏈?zhǔn)健苯Y(jié)構(gòu),同時(shí)通過log可以看出創(chuàng)建過程拔妥。

企業(yè)微信截圖_ff493fa9-63a7-44ce-87d0-5d7ee4a0f872.png
二叉搜索樹的例子.jpg

遍歷

/**
 *  先序遍歷:先訪問根忿危,再遍歷左子樹,再遍歷右子樹没龙。典型的遞歸思想铺厨。
 *
 *  @param rootNode 根節(jié)點(diǎn)
 *  @param handler  訪問節(jié)點(diǎn)處理函數(shù)
 */
+ (void)preOrderTraverseTree:(BinaryTreeNode *)rootNode handler:(void(^)(BinaryTreeNode *treeNode))handler {
    if (rootNode) {
        // 先訪問
        if (handler) {
            handler(rootNode);
        }
        // 再遍歷左右子樹
        [BinaryTree preOrderTraverseTree:rootNode.leftChild handler:handler];
        [BinaryTree preOrderTraverseTree:rootNode.rightChild handler:handler];
    }
}

/**
 *  中序遍歷
 *  先遍歷左子樹缎玫,再訪問根,再遍歷右子樹
 *
 *  @param rootNode 根節(jié)點(diǎn)
 *  @param handler  訪問節(jié)點(diǎn)處理函數(shù)
 */
+ (void)inOrderTraverseTree:(BinaryTreeNode *)rootNode handler:(void(^)  (BinaryTreeNode *treeNode))handler {
    if (rootNode) {
        // 先遍歷左子樹
        [BinaryTree inOrderTraverseTree:rootNode.leftChild handler:handler];
        
        // 訪問節(jié)點(diǎn)
        if (handler) {
            handler(rootNode);
        }
    
        // 最后遍歷右子樹
        [BinaryTree inOrderTraverseTree:rootNode.rightChild handler:handler];
    }
}

/**
 *  后序遍歷
 *  先遍歷左子樹解滓,再遍歷右子樹赃磨,再訪問根
 *
 *  @param rootNode 根節(jié)點(diǎn)
 *  @param handler  訪問節(jié)點(diǎn)處理函數(shù)
 */
+ (void)postOrderTraverseTree:(BinaryTreeNode *)rootNode handler:(void(^)(BinaryTreeNode *treeNode))handler {
    if (rootNode) {
        // 先遍歷左右子樹
        [BinaryTree postOrderTraverseTree:rootNode.leftChild handler:handler];
        [BinaryTree postOrderTraverseTree:rootNode.rightChild handler:handler];
        
        // 最后訪問節(jié)點(diǎn)
        if (handler) {
            handler(rootNode);
        }
    }
}

測(cè)試一下:

// 先序遍歷
- (IBAction)preOrderButtonTouched:(id)sender {
    NSMutableArray<NSNumber *> *preArray = [NSMutableArray array];
    [BinaryTree preOrderTraverseTree:self.rootNode handler:^(BinaryTreeNode * _Nonnull treeNode) {
        [preArray addObject:[NSNumber numberWithInteger:treeNode.value]];
    }];
    NSLog(@"先序遍歷:%@", preArray);
}

// 中序遍歷
- (IBAction)inOrderButtonTouched:(id)sender {
    NSMutableArray<NSNumber *> *inArray = [NSMutableArray array];
    [BinaryTree inOrderTraverseTree:self.rootNode handler:^(BinaryTreeNode * _Nonnull treeNode) {
        [inArray addObject:[NSNumber numberWithInteger:treeNode.value]];
    }];
    NSLog(@"中序遍歷:%@", inArray);
}

// 后序遍歷
- (IBAction)postOrderButtonTouched:(id)sender {
    NSMutableArray<NSNumber *> *postArray = [NSMutableArray array];
    [BinaryTree postOrderTraverseTree:self.rootNode handler:^(BinaryTreeNode * _Nonnull treeNode) {
        [postArray addObject:[NSNumber numberWithInteger:treeNode.value]];
    }];
    NSLog(@"后序遍歷:%@", postArray);
}

根據(jù)二叉樹的圖,可以查看log中的遍歷順序是否符合:

企業(yè)微信截圖_aee2f449-badd-4332-a0c5-9f00bbb7b2fe.png

翻轉(zhuǎn)

/**
 * 翻轉(zhuǎn)二叉樹(又叫:二叉樹的鏡像)
 *
 * @param rootNode 根節(jié)點(diǎn)
 *
 * @return 翻轉(zhuǎn)后的樹根節(jié)點(diǎn)(其實(shí)就是原二叉樹的根節(jié)點(diǎn))
 */
+ (BinaryTreeNode *)invertBinaryTree:(BinaryTreeNode *)rootNode {
    // 空節(jié)點(diǎn)
    if (!rootNode) {
        return nil;
    }
    
    // 沒有子節(jié)點(diǎn)
    if (!rootNode.leftChild && !rootNode.rightChild) {
        return rootNode;
    }
    
    // 左右子樹遞歸
    [BinaryTree invertBinaryTree:rootNode.leftChild];
    [BinaryTree invertBinaryTree:rootNode.rightChild];
    
    // 左右節(jié)點(diǎn)交換
    BinaryTreeNode *tempNode = rootNode.leftChild;
    rootNode.leftChild = rootNode.rightChild;
    rootNode.rightChild = tempNode;
    return rootNode;
}

測(cè)試:將一開始創(chuàng)建的二叉搜索樹翻轉(zhuǎn)洼裤,然后畫出圖邻辉,與原圖比較

企業(yè)微信截圖_dfc9287b-de1e-43ec-bb82-51668d97a0b1.png
二叉搜索樹翻轉(zhuǎn).jpg

Demo地址

Demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市腮鞍,隨后出現(xiàn)的幾起案子值骇,更是在濱河造成了極大的恐慌,老刑警劉巖移国,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吱瘩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡迹缀,警方通過查閱死者的電腦和手機(jī)使碾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祝懂,“玉大人部逮,你說我怎么就攤上這事∩┮祝” “怎么了兄朋?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)怜械。 經(jīng)常有香客問我颅和,道長(zhǎng),這世上最難降的妖魔是什么缕允? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任峡扩,我火速辦了婚禮,結(jié)果婚禮上障本,老公的妹妹穿的比我還像新娘教届。我一直安慰自己,他們只是感情好驾霜,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布案训。 她就那樣靜靜地躺著,像睡著了一般粪糙。 火紅的嫁衣襯著肌膚如雪强霎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天蓉冈,我揣著相機(jī)與錄音城舞,去河邊找鬼轩触。 笑死,一個(gè)胖子當(dāng)著我的面吹牛家夺,可吹牛的內(nèi)容都是我干的脱柱。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼拉馋,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼褐捻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起椅邓,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤柠逞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后景馁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體板壮,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年合住,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绰精。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡透葛,死狀恐怖笨使,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情僚害,我是刑警寧澤硫椰,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站萨蚕,受9級(jí)特大地震影響靶草,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岳遥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一奕翔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浩蓉,春花似錦派继、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至讯泣,卻和暖如春纫普,著一層夾襖步出監(jiān)牢的瞬間阅悍,已是汗流浹背好渠。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工昨稼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拳锚。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓假栓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親霍掺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子匾荆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361