求矩陣四叉樹的四進制和十進制Morton碼


    Yogurt是一名學GIS的學生,今天要跟大家分享的是四叉樹這種空間索引方式的Morton編碼方法,接下來我將在小課堂中簡單介紹一下空間索引以及其幾種編碼方式~~

---------------------------------------------------------yogurt小課堂開課啦--------------------------------------------------------

    GIS所涉及到的都是有關空間的數據信息,即也屬於所謂的大數據了,那么怎么將客觀的物體對象存儲到計算機中,以及怎么從計算機中讀取所需要的數據呢?

    首先我們要知道計算機的存儲器有內存和外存,內存空間小但是讀寫快,外存空間大卻讀寫慢,訪問外存所花費的時間是訪問內存的十萬倍以上!在GIS的實際應用中大量的數據都是存儲在外存上的,想象一下如果這些數據全都雜亂無章的堆放在那里,那么每需要查詢一個數據就需要掃描整個數據文件,這樣訪問磁盤的代價是非常大的,嚴重影響了系統效率!所以,我們必須記錄好每個數據存放的位置,以便於組織和管理,在這個過程中就需要用到索引技術啦!

    【(這里引自我老師的課件哈,低調低調!!!)

    從傳統的索引技術觀點來看,可以把空間索引技術大致分為四大類:基於R樹,基於Hashing,基於二叉樹,基於空間填充。

    在建立索引時,按照划分區域是否與空間對象的分布特征有關的標准,空間索引又可以分為兩大類:無關的(網格索引、四叉樹),有關的(BSP樹、KD樹、KDB樹、R樹及其變種樹)。

    我們來看看幾種索引方法的實際應用:

    (1)ESRI的ArcSDE采用的是固定格網索引;

    (2)目前國內外主要的空間數據庫如ESRI的ArcView,Mapinfo公司的Maoinfo和Informix的GeoSpatial DataBlade采用的是R樹系列作為空間索引的方式;

    (3)Oracle公司的Spatial同時采用固定格網索引以及R樹索引;

    (4)中國地質大學的MapGIS和中科院的SuperMap采用的是四叉樹。

     以上來自我的一個大牛老師的PPT~~】

    好啦,既然今天要講矩陣四叉樹的Morton編碼,那么接下來就介紹一下四叉樹以及Morton碼的編碼規則吧:

   【四叉樹】:

    區域型物體的四叉樹表示方法最早出現在加拿大地理信息系統CGIS中,20世紀80年代以來,四叉樹在圖象分割、數據壓縮、 地理信息系統等方面進行了大量的研究,對四叉樹數據結構提出了許多編碼方案。四叉樹分為常規四叉樹與線性四叉樹,下圖簡單的說明了兩者的區別:(不要嫌棄我字丑!!!)

    編碼規定:

       

   【線性四叉樹的編碼方式】: 例如有這樣一個矩陣線性四叉樹,以紅色圈中的9的編碼為例,有自上而下的方法和自下而上的方法:

       

   (1)基於深度和層次碼線性四叉樹編碼:(自上而下的方法)

   層次碼:第一層(在位置2,用兩位二進制表示為:10),第二層(在位置1,用兩位二進制表示為:01),第三層(在位置2,用兩位二進制表示為:10);

   深度碼:有3層深,(用四位二進制表示為:0011);

   “9”的位置編碼為:10 01 10 0011,該位置碼的十進制為2^0+2^1+2^5+2^6+2^9=611.

   (2)基於四進制的線性四叉樹編碼:

   (自上而下的方法):第一層2,第二層1,第三層2,位置碼:212

   (自下而上的方法,說明四進制編碼的過程):二進制的行列號Iyb、Ixb(從第0行0列開始),四進制編碼M=2*Iyb+ Ixb;那么這里就是:第5行(101)第2列(010):M=2*101+10=212

   (3)基於十進制的線性四叉樹編碼:

   (自下而上的方法,說明四進制編碼的過程):二進制的行列號Iyb、Ixb(從第0行0列開始),十進制編碼M=奇數位用列號填充,偶數位用行號填充;那么這里就是:第5行(101)第2列(010):M=10 01 10

   (4)在相鄰四個碼中若屬性值相同,進行合並,除去最低位得到合並后的新編碼。

-----------------------------------------------------------下課啦!!!--------------------------------------------------------------

 

 

編寫該程序的思路:

第一步:讀入矩陣四叉樹,並將其輸出;

第二步:利用four_decimal函數得到每一個位置的四進制M碼,利用Change函數得到規定格式的三位四進制M碼;最后利用checkcombine_four函數,將屬性值一樣的位置的M碼合並,並輸出;

第三步:同第二步類似,利用ten_decimal函數得到每一個位置的十進制M碼,利用checkcombine_ten函數,將屬性值一樣的位置的M碼合並,並輸出。

 

具體實現過程:

(1)將十進制行列號轉換為二進制:利用函數Tobinary :

(2)得到四進制M碼:利用函數four_decimal:

(3)得到十進制M碼:利用函數ten_decimal:(注意按位交錯)

(4)對屬性值一樣的M碼進行合並的處理操作checkcombine_ten:(以十進制為例)

在第二層里:(方法與第一層類似,只是合並條件變成了w==2)

最后輸出數組即可,對於四進制的M碼,由於合並時還要除去最低位的,所以需要特殊處理(便於輸出):如在合並第一層時,給第二三位賦予標志值99999999:

 

合並第二層時,給第三位賦予標志值99999999:

 

輸出時:

 

好啦,接下來是整體代碼:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

typedef int newc[3];
typedef int ceng[2];

void read(int a[][8]);                             //讀入矩形四叉樹
int Tobinary(int k);                               //將十進制的行列號k轉換為二進制.
int eq(int m, int n);                              //判斷m和n是否相等,相等則返回1,否則返回0.
void judge_four(int a[][8], newc b[][8], ceng c[4]);//判斷數組c表示的矩形范圍內的值是否一樣,若一樣就更新數組b.
void judge_ten(int a[][8], int b[][8], ceng c[4]); 
void checkcombine_four(int a[][8], newc b[][8]);   //將屬性值一樣的單元進行合並.
void checkcombine_ten(int a[][8], int b[][8]);     
void Change(int m[][8], newc n[][8]);              //將四進制的M碼按照規定格式輸出.
void four_decimal(int b[][8]);                     //四進制編碼.
void ten_decimal(int c[][8]);                      //十進制編碼.
void output_i(int a[][8]);                         //輸出int型數組.
void output_c(newc a[][8]);                        //輸出newc型數組.

void main()
{
    int a[8][8], b[8][8], c[8][8];
    newc bb[8][8];
    read(a);
    printf("矩陣四叉樹為:\n");
    output_i(a);

    four_decimal(b);
    Change(b, bb);
    checkcombine_four(a,bb);
    printf("\n四叉樹對應的四進制編碼為:\n");
    output_c(bb);

    ten_decimal(c);
    checkcombine_ten(a,c);
    printf("\n四叉樹對應的十進制編碼為:\n");
    output_i(c);
}

void read(int a[][8])
{
    FILE *fp = fopen("四叉樹.txt","r");
    if (!fp)
        exit;
    else
    for (int i = 0; i < 8;i++)
    for (int j = 0; j < 8; j++)
        fscanf(fp, "%d", &a[i][j]);
    fclose(fp);
}

int Tobinary(int k)
{
    int s[10],rem,i=0,t=0;
    do
    {
        rem = k % 2;
        k = k / 2;
        s[i++] = rem;
    } while (k != 0);   //當十進制數是0時也要進行一遍此循環,所以必須用do……while循環,而不是while循環
    for (int j = --i; j >= 0; j--)
    {
        t += s[j] * pow(10.0, j);
    }
    return t;
}

int eq(int m, int n)
{
    if (m == n)
        return 1;
    else
        return 0;
}

void judge_four(int a[][8], newc b[][8], ceng c[4])
{
    for (int i = 0; i < 4; i++)
    {
        int w = 0;
        for (int m = c[i][0]; m <c[i][0] + 2; m++)
        for (int n = c[i][1]; n <c[i][1] + 1; n++)
            w += eq(a[m][n], a[m][n + 1]);
        if (w == 2)//4個值屬性一樣
        {
            for (int m = c[i][0]; m <c[i][0] + 2; m++)
            for (int n = c[i][1]; n < c[i][1] + 2; n++)
            {
                *b[m][n] = *b[(c[i][0])][(c[i][1])];
                *(b[m][n] + 1) = *(b[(c[i][0])][(c[i][1])] + 1);
                *(b[m][n] + 2) = 99999999;
            }
        }
    }
}

void judge_ten(int a[][8], int b[][8], ceng c[4])
{
    for (int i = 0; i < 4; i++)
    {
        int w = 0;
        for (int m = c[i][0]; m <c[i][0]+2; m++)
        for (int n = c[i][1]; n <c[i][1]+1; n++)
            w += eq(a[m][n], a[m][n + 1]);
        if (w == 2)//4個值屬性一樣
        {
            for (int m = c[i][0]; m <c[i][0] + 2; m++)
            for (int n = c[i][1]; n < c[i][1] + 2; n++)
            {
                b[m][n] = b[(c[i][0])][(c[i][1])];
            }
        }
    }
}

void checkcombine_ten(int a[][8], int b[][8])
{
    //第一層
    ceng c[4] = { { 0, 0 }, { 0, 4 }, { 4, 0 }, { 4, 4 } };
    for (int i = 0; i < 4; i++)
    {
        int w = 0;
        for (int m = c[i][0]; m < 4; m++)
        for (int n = c[i][1]; n < 3; n++)
            w += eq(a[m][n], a[m][n + 1]);
        if (w == 12)//16個值屬性一樣
        {
            for (int m = c[i][0]; m < c[i][0] + 4; m++)
            for (int n = c[i][1]; n < c[i][1] + 4; n++)
            {
                b[m][n] = b[(c[i][0])][(c[i][1])];
            }
        }
    }
    //第二層
    ceng d[4] = { { 0, 0 }, { 0, 2 }, { 2, 0 }, { 2, 2 } },
        e[4] = { { 0, 4 }, { 0, 6 }, { 2, 4 }, { 2, 6 } },
        f[4] = { { 4, 0 }, { 4, 2 }, { 6, 0 }, { 6, 2 } },
        g[4] = { { 4, 4 }, { 4, 6 }, { 6, 4 }, { 6, 6 } };
    judge_ten(a, b, d);
    judge_ten(a, b, e);
    judge_ten(a, b, f);
    judge_ten(a, b, g);
}

void checkcombine_four(int a[][8], newc b[][8])
{
    //第一層
    ceng c[4] = { { 0, 0 }, { 0, 4 }, { 4, 0 }, { 4, 4 } };
    for (int i = 0; i < 4; i++)
    {
        int w = 0;
        for (int m = c[i][0]; m < 4; m++)
        for (int n = c[i][1]; n < 3; n++)
            w += eq(a[m][n], a[m][n + 1]);
        if (w == 12)//16個值屬性一樣
        {
            for (int m = c[i][0]; m < c[i][0] + 4; m++)
            for (int n = c[i][1]; n < c[i][1] + 4; n++)
            {
                *b[m][n] =*b[(c[i][0])][(c[i][1])];
                *(b[m][n] + 1) =99999999;
                *(b[m][n] + 2) =99999999;
            }
        }
    }
    //第二層
    ceng d[4] = { { 0, 0 }, { 0, 2 }, { 2, 0 }, { 2, 2 } },
        e[4] = { { 0, 4 }, { 0, 6 }, { 2, 4 }, { 2, 6 } },
        f[4] = { { 4, 0 }, { 4, 2 }, { 6, 0 }, { 6, 2 } },
        g[4] = { { 4, 4 }, { 4, 6 }, { 6, 4 }, { 6, 6 } };
    judge_four(a, b, d);
    judge_four(a, b, e);
    judge_four(a, b, f);
    judge_four(a, b, g);
}

void Change(int m[][8], newc n[][8])
{
    int t[3];
    int q;
    for (int i = 0; i < 8;i++)
    for (int j = 0; j < 8; j++)
    {
        q = m[i][j];
        t[0] = q / 100;
        q = q % 100;    
        t[1] = q / 10;
        q = q % 10;
        t[2] = q;
        *n[i][j] = *t;             //數組賦值,數組名稱不能直接做左值
        *(n[i][j] + 1) = *(t + 1);
        *(n[i][j] + 2) = *(t + 2);
    }
}

void four_decimal(int b[][8])
{
    for (int i = 0; i < 8;i++)
    for (int j = 0; j < 8;j++)
    {
        int m=Tobinary(i);
        int n=Tobinary(j);
        b[i][j] = 2 * m + n;
    }
}

void ten_decimal(int c[][8])
{
    for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++)
    {
        int m = Tobinary(i);
        int n = Tobinary(j);
        int t[8];
        t[0] = m / 1000;
        m = m % 1000;
        t[2] = m / 100;
        m = m % 100;
        t[4] = m / 10;
        m = m % 10;
        t[6] = m;

        t[1] = n / 1000;
        n = n % 1000;
        t[3] = n / 100;
        n = n % 100;
        t[5] = n / 10;
        n = n % 10;
        t[7] = n;

        int y = 0;
        for (int w = 0; w < 8; w++)
        {
            y+= t[w] * pow(2.0,7-w);
        }    
        c[i][j] = y;
    }
}

void output_i(int a[][8])
{
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            printf("%6d", a[i][j]);
        }
        printf("\n");
    }
}

void output_c(newc a[][8])
{
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        if (*(a[i][j] + 1)==99999999&&*(a[i][j] + 2)==99999999)
            printf("%6d", *a[i][j]);
        else if (*(a[i][j] + 2) == 99999999)
            printf("%5d%d", *a[i][j], *(a[i][j] + 1));
        else
            printf("%4d%d%d", *a[i][j], *(a[i][j] + 1), *(a[i][j] + 2));
        printf("\n");
    }
}
View Code

 

最后結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM