一、数组实现二叉树(下标从0开始)

#include <stdio.h>
typedef struct _TreeNode{
    int data;
    bool IsEmpty;       //结点是否为空  // 因为我们的二叉树不一定是满二叉树,中间可能有一些节点不存在 // 值为1代表空
}TreeNode;


// 初始化
void InitTreeNode(TreeNode t[],int len){
    for(int i=0;i<len;i++)
        t[i].IsEmpty = 1;
}


bool IsEmpty(TreeNode t[],int len,int idx){
    if(idx >= len || idx < 0) return 1;         // 修改为0
    
    return t[idx].IsEmpty;
}

// father = (child-1)/2   or  father = child/2 - 1
int findFather(TreeNode t[],int len,int idx){
    if(idx == 0) return -1;         //特判根节点没有父节点      // 特判也修改为0
    int fatheridx = (idx-1) / 2;
    if(IsEmpty(t,len,fatheridx)) return -1;
    return fatheridx;
}

// lchild = father*2 + 1
int findLchild(TreeNode t[],int len,int idx){
    int lchild = idx*2 + 1;
    if(IsEmpty(t,len,lchild)) return -1;
    return lchild;
}

// rchild = father*2+2
int findRchild(TreeNode t[],int len,int idx){
    int rchild = idx*2 + 2;
    if(IsEmpty(t,len,rchild)) return -1;
    return rchild; 
}

//实现前序遍历, 从下表为idx的节点开始前序遍历
int PreorderTree(TreeNode t[],int len,int idx){
    if(IsEmpty(t,len,idx)) return 0;
    printf("%d\n",t[idx].data);
    PreorderTree(t,len,findLchild(t,len,idx));
    PreorderTree(t,len,findRchild(t,len,idx));
    return 0;
}

int InorderTree(TreeNode t[],int len,int idx){
    if(IsEmpty(t,len,idx)) return 0;
    InorderTree(t,len,findLchild(t,len,idx));
    printf("%d\n",t[idx].data);
    InorderTree(t,len,findRchild(t,len,idx));
    return 0;
}
int PostorderTree(TreeNode t[],int len,int idx){
    if(IsEmpty(t,len,idx)) return 0;
    PostorderTree(t,len,findLchild(t,len,idx));
    PostorderTree(t,len,findRchild(t,len,idx));
    printf("%d\n",t[idx].data);
    return 0;
}


int main(){
    TreeNode Td[100];            // 这里的二叉树节点要从0开始
    int fatheridx;
    int testLen = 7;          // IsEmpty 的判断是 >=Len 所以这里加一个1
    for(int i=0;i<=testLen;i++){
        Td[i].data = i+1;
        Td[i].IsEmpty = 0;
    }
    PreorderTree(Td,testLen,0);
    // InorderTree(Td,testLen,0);
    // PostorderTree(Td,testLen,0);
    return 0;
}

二、数组实现二叉树(下标从1开始)

#include <stdio.h>
typedef struct _TreeNode{
    int data;
    bool IsEmpty;       //结点是否为空  // 因为我们的二叉树不一定是满二叉树,中间可能有一些节点不存在 // 值为1代表空
}TreeNode;


// 初始化
void InitTreeNode(TreeNode t[],int len){
    for(int i=0;i<len;i++)
        t[i].IsEmpty = 1;
}


bool IsEmpty(TreeNode t[],int len,int idx){
    if(idx >= len || idx < 1) return 1;
    
    return t[idx].IsEmpty;
}

// father = child / 2
int findFather(TreeNode t[],int len,int idx){
    // if(idx == 1) return -1;         //特判根节点没有父节点 ,不加也没事,但下表从0开始的时候必须加
    int fatheridx = idx / 2;
    if(IsEmpty(t,len,fatheridx)) return -1;
    return fatheridx;
}

// lchild = father*2
int findLchild(TreeNode t[],int len,int idx){
    int lchild = idx*2;
    if(IsEmpty(t,len,lchild)) return -1;
    return lchild;
}

// rchild = father*2+1
int findRchild(TreeNode t[],int len,int idx){
    int rchild = idx*2+1;
    if(IsEmpty(t,len,rchild)) return -1;
    return rchild; 
}

//实现前序遍历, 从下表为idx的节点开始前序遍历
int PreorderTree(TreeNode t[],int len,int idx){
    if(IsEmpty(t,len,idx)) return 0;
    printf("%d\n",t[idx].data);
    PreorderTree(t,len,findLchild(t,len,idx));
    PreorderTree(t,len,findRchild(t,len,idx));
    return 0;
}

int InorderTree(TreeNode t[],int len,int idx){
    if(IsEmpty(t,len,idx)) return 0;
    InorderTree(t,len,findLchild(t,len,idx));
    printf("%d\n",t[idx].data);
    InorderTree(t,len,findRchild(t,len,idx));
    return 0;
}
int PostorderTree(TreeNode t[],int len,int idx){
    if(IsEmpty(t,len,idx)) return 0;
    PostorderTree(t,len,findLchild(t,len,idx));
    PostorderTree(t,len,findRchild(t,len,idx));
    printf("%d\n",t[idx].data);
    return 0;
}


int main(){
    TreeNode Td[100];            // 这里的二叉树节点要从一开始
    int fatheridx;
    int testLen = 7+1;          // IsEmpty 的判断是 >=Len 所以这里加一个1
    for(int i=1;i<=testLen;i++){
        Td[i].data = i;
        Td[i].IsEmpty = 0;
    }
    PreorderTree(Td,testLen,1);
    // InorderTree(Td,testLen,1);
    // PostorderTree(Td,testLen,1);
    return 0;
}

三、并查集及其优化思路

#include <stdio.h>
#define MAXSIZE 50
int UFSets[MAXSIZE];

void InitUFSets(int S[]){
    for(int i=0;i<MAXSIZE;i++){
        S[i] = -1;
    }
}

int find(int S[],int x){
    if(S[x] == -1) return x;           // -1说明到底了
    return find(S,S[x]);
}

int pathCompFind(int S[],int x){         // 路径压缩策略优化Find 操作
    if(S[x] >= 0){
        S[x] = find(S,S[x]); 
        return S[x];
    }
    return x;
}


bool UnionElem(int S[],int elem1,int elem2){    //王道书上是直接合并的root,而不是元素成员
    int first = find(S,elem1);
    int second = find(S,elem2);
    if(first != second){
        printf("%d -- %d\n",first,second);
        S[second] = first;
        return 1;
    }
    return 0;
}

bool UnionRoot(int S[],int Root1,int Root2){
    if(Root1 == Root2) return 0;    //比较两个根是否来自同一集合
    S[Root2] = Root1;               // 将根Root2连接到Root1上
    return 1;
}

bool optUnionRoot(int S[],int Root1,int Root2){
    if(Root1 == Root2) return 0;
    if(S[Root2] > S[Root1]){   // Root2 结点数更少         // 因为初始化的时候S的值全为 -1  所以 若S[Root1]与S[Root2]相加后为更小的负数
                                                            //较小的树,树较大,这也是为什么 S[Root1] >= S[Root2]时 却把Root2合并到Root1中的原因
        S[Root1] += S[Root2];       // 累加节点个数
        S[Root2] = Root1;
    }else{
        S[Root2] += S[Root1];
        S[Root1] = Root2;
    }
    return 1;
}

void debug(){
    for(int i=0;i<MAXSIZE;i++){
        printf("%d ",UFSets[i]);
    }
    puts("");
}

int main(){
    InitUFSets(UFSets);
    int arr[100] = {0,1,2,3,4,5,6,7,8,9};
    for(int i=0;i<=10;i++){
        UnionElem(UFSets,arr[i*2],arr[i*2+1]);
        // 0 -- 1
        // 2 -- 3
        // 4 -- 5
        // 6 -- 7
        // 8 -- 9
    }
    UnionElem(UFSets,1,3);
    UnionElem(UFSets,5,7);
    // 0 -- 1
    // 2 -- 3
    // 4 -- 5
    // 6 -- 7
    // 8 -- 9
    // 0 -- 2
    // 4 -- 6

    UnionElem(UFSets,1,6);
    UnionElem(UFSets,2,7);
    // debug();



    return 0;
}
 
08-07 10:13