2015-07-21 49 views
0

我正試圖建立一個基於遞歸的二維樹。我可以總結算法如下:kd-tree中的無限遞歸

>  ALGORITHM BuildKDTree(P,depth) 
>  1. if P contains only one point 
>  2. then return a leaf storing this point 
>  3. else if depth is even 
>  4. then split P with a vertical line through median x into P1 and P2 (left and right of the line, respectively) 
>  5. else split P with a horizontal line through median y into P1 and P2 like before 
>  6. RECURSION STEP -> v_left = BuildKDTree(P1,depth+1) 
>  7. RECURSION STEP -> v_right = BuildKDTree(P2,depth+1) 
>  8. Create a node v storing the line, make v_left the left child and v_right the right child 
>  9. return the node v 

因爲這是我第一次實現遞歸,我有很多相關的問題。到目前爲止,我寫的代碼似乎處於無限循環,直到引發段錯誤。我目前無法找到代碼中的錯誤,我希望得到一些幫助。

// Point 
struct Point{ 
    int idx; 
    double xpos; 
    double ypos; 
}; 

// Node in the k-d tree 
struct Node{ 
    char type; 
    Point coord; 
    Node* leftChild; 
    Node* rightChild; 
    double split; 
}; 

// Function to find the median point 
int findMedian(const vector<Point>& P, char line){ 

    vector<double> positions; 
    map<double,int> indices; 

    // Store the corresponding positions (vertical or horizontal splitting) 
    switch (line){ 

     case 'x': 

      for(auto p: P){ 
       positions.push_back(p.xpos); 
       indices.insert(pair<double,int>(p.xpos,p.idx)); 
      } 

      break; 

     case 'y': 

      for(auto p: P){ 
       positions.push_back(p.ypos); 
       indices.insert(pair<double,int>(p.ypos,p.idx)); 
      } 

      break; 
    } 

    sort(positions.begin(), positions.end()); 
    cout << positions.size() << endl; 
    int middle_pt = (int)floor(positions.size()/2); 
    cout << indices[positions[middle_pt]] << "\t" << middle_pt << "\t" << positions[middle_pt] << endl; 
    return (indices[positions[middle_pt]]); 

} 

// Function to build a k-d tree 
Node buildKDTree(vector<Point> P, int depth){ 

    Node v; 

    // if P contains only one point, return a leaf storing this point; 
    // else if depth is even, split P with a vertical line through the median x .. 
    // .. into P1 (left of l) and P2 (right of l); 
    // when the depth is odd, do the vice versa. 
    if(P.size() == 1){ 

     cout << "I am at the leaf!" << endl; 

     v.coord = P[0]; 
     v.type = 'l'; 
     return v; 
    } 
    else if(P.size() < 1){ 
     cout << "Points size smaller than 1 " << P.size() << endl; 

     v.type = 'n'; 
     return v; 
    } 
    else{ 

     vector<Point> P1; // left of median 
     vector<Point> P2; // right of median 

     if(depth % 2 == 0) { 

      // Verical line through median x 
      char line = 'x'; 
      v.type = line; 
      int mid_idx = findMedian(P, line); 
      v.split = P[mid_idx].xpos; 
      v.coord = P[mid_idx]; 
      for(auto p: P){ 
       if(p.xpos < v.split){ 
        //cout << "Through x, left " << "\t" << p.xpos << "\t" << mid_coord << endl; 
        P1.push_back(p); 
       } 
       else{ 
        //cout << "Through x, right " << "\t" << p.xpos << "\t" << mid_coord << endl; 
        P2.push_back(p); 
       } 
      } 

     } 
     else{ 

      // Horizontal line through median y 
      char line = 'y'; 
      v.type = line; 
      int mid_idx = findMedian(P, line); 
      v.split = P[mid_idx].ypos; 
      v.coord = P[mid_idx]; 
      for(auto p: P){ 
       if(p.ypos < v.split){ 
        //cout << "Through y, left " << "\t" << p.ypos << "\t" << mid_coord << endl; 
        P1.push_back(p); 
       } 
       else{ 
        //cout << "Through y, right " << "\t" << p.ypos << "\t" << mid_coord << endl; 
        P2.push_back(p); 
       } 
      } 

     } 

     cout << "depth is before at " << depth << endl; 
     Node temp1 = buildKDTree(P1, depth+1); 
     depth = 2; 
     cout << "depth is after at " << depth << endl; 
     Node temp2 = buildKDTree(P2, depth+1); 
     v.leftChild = &temp1; 
     v.rightChild = &temp2; 

     return v; 
    } 

} 

// +++++++ 


int main(int argc, char *argv[]){ 

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    //++ Get the data 
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

    // Choose the data to be used 
    const int nsamp = samplePostData;  // Sampling interval 
    const double dtSamp = nsamp*dt;   // Time units between two data points 

    // Instantiate the data structure 
    vector<Cell> cells(M); 

    // Set filenames 
    char * x_input_file = argv[1];  // Filename for the x data 
    char * y_input_file = argv[2];  // Filename for the y data 

    // Read the data to the cells 
    int sample_cnt = -1; 
    int sample_data = 1; 
    char getX = 'x'; 
    readData(cells, x_input_file, getX, sample_cnt, sample_data); 
    sample_cnt = -1; 
    char getY = 'y'; 
    readData(cells, y_input_file, getY, sample_cnt, sample_data); 

    // Set general simulation variables 
    Data simData; 
    simData.setNumStep(cells[0].xpos.size()); 
    simData.setNumDelay(sqrt(cells[0].xpos.size())); 
    simData.setNumTotalDelay(); 

    const double T = simData.getNumStep();    // Total time 
    const double D = simData.getNumDelay();    // Last delay time 
    const double TD = simData.getNumTotalDelay();  // Total time - last delay time 

    // Set the box 
    Box box; 
    box.setWidth(boxSize_x); 
    box.setHeight(boxSize_y); 

    const double Lx = box.getWidth(); 
    const double Ly = box.getHeight(); 

    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 


    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    //++ Do the analysis 
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

    vector<Point> points; 
    int i = 1000; 
    for(int m = 0; m < M; m++){ 
     Point point_temp; 
     point_temp.xpos = (cells[m].xpos[i] - Lx*ifloor(cells[m].xpos[i]/Lx)); 
     point_temp.ypos = (cells[m].ypos[i] - Ly*ifloor(cells[m].ypos[i]/Ly)); 
     point_temp.idx = m; 
     points.push_back(point_temp); 
    } 
    vector<Node> tree; 
    int depth = 2; 
    tree.push_back(buildKDTree(points, depth)); 
    cout << tree.size() << endl; 
// for(auto j: tree){ 
//  cout << j.type << " " << j.coord.idx << " " << j.coord.xpos << " " << j.coord.ypos << " " << j.leftChild->coord.idx << " " << j.rightChild->coord.idx << " " << j.leftChild->coord.xpos << " " << j.rightChild->coord.ypos << "\n"; 
// } 


} 
+0

聽起來像「請爲我調試」。我的建議是自己調試它。這是一項挑戰,如果您接受挑戰,您將從中獲得最大收益。另一點是:從小開始。學習單元測試。學習[TDD](https://en.wikipedia.org/wiki/Test-driven_development)。 – TobiMcNamobi

回答

1

問題是你不檢查標記相同點的中位數的兩倍。很容易出現這種情況(特別是在密集系統中)中線上有多個點。如果您沒有明確標記之前用作中位數的點,那麼您將再次使用它們,這將在樹中創建無限遞歸。

我的建議是爲每個點做一個布爾數組,當你用這些點作爲中位數時,只需標記它們,以便以後不再使用它們。