2011-11-15 6 views
16

मैं कंप्यूटर विज्ञान वर्ग के लिए एक ढेर कार्यान्वयन कर रहा हूं, और मैं सोच रहा था कि निम्नलिखित रिकर्सिव फ़ंक्शन एक सरणी ऑब्जेक्ट से ढेर बना देगा जो पहले से ही ढेर नहीं था। कोड इस प्रकार है:क्या मैं "हेपीफाइ" एल्गोरिदम सही ढंग से कार्यान्वित कर रहा हूं?

void Heap::Heapify(int i) 
{ 
    int temp, l, r, heapify; 
    l = LeftChild(i);// get the left child 
    r = RightChild(i);// get the right child 

    //if one of the children is bigger than the index 
    if((Data[i] < Data[l]) || (Data[i]< Data[r])) 
    { 
     //if left is the bigger child 
     if(Data[l] > Data[r]) 
     { 
      //swap parent with left child 
      temp = Data[i]; 
      Data[i] = Data[l]; 
      Data[l] = temp; 
      heapify = l; // index that was swapped 
     } 
     //if right is the bigger child 
     else 
     { 
      //swap parent with right child 
      temp = Data[i]; 
      Data[i] = Data[r]; 
      Data[r] = temp; 
      heapify = r; // index that was swapped 
     } 
     // do a recursive call with the index 
     //that was swapped 
     Heapify(heapify); 
    } 
} 

विचार यह है कि यदि आप देखते हैं दिए गए इंडेक्स पर डेटा बड़ा की तुलना में यह के सभी बच्चों है है। यदि ऐसा है, तो फ़ंक्शन कोई समस्या नहीं समाप्त होता है। अन्यथा, यह देखने के लिए जांचें कि कौन सा सबसे बड़ा (बाएं या दाएं बच्चे) है, और उसके बाद सूचकांक के साथ स्वैप करता है। तब हेपफाइफ़ को इंडेक्स में बुलाया जाता है जहां स्वैपिंग हुई।

#ifndef HEAP_H 
#define HEAP_H 
//Programmer: Christopher De Bow 
//Date: november 15, 2011 

class Heap 
{ 
private: 
    int Data [100]; 
    int Parent(int); 
    int RightChild(int); 
    int LeftChild(int); 
    void Heapify(int); 
    void BuildHeap(); 

public: 
    Heap(); 
    void insert(); 
    void HeapSort(); 
    void ExtractMaximum(); 
    int Maximum(); 
    void PrintHeap(); 
    int heapsize; 
    void SetData(int[]); 
}; 

#endif 

और कार्यान्वयन फ़ाइल:


यहाँ हेडर फाइल है:

ildjarn के अनुरोध से, मैं अपने सवाल का जवाब देने में सहायता करने के मेरा पूरा वर्ग परिभाषा और कार्यान्वयन फ़ाइलों सहित कर रहा हूँ

#include <iostream> 
#include "Heap.h" 
using namespace std; 
//Programmer: Christopher De Bow 
//Date: november 15, 2011 

Heap::Heap() 
{ 
    int init [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
    heapsize = 10; 
    SetData(init); 
} 

int Heap::Parent(int index) 
{ 
    int Rval; 
    if(index%2 == 0)// if the index is even 
    { 
     Rval = ((index-1)/2); 
    } 
    else// if the index is odd 
    { 
     Rval = (index/2); 
    } 
    return Rval; 
} 

int Heap::RightChild(int arrplace) 
{ 
    int ret; 
    ret = ((2*arrplace)+2); //rightchild is index times 2 plus 2 
    return ret; 
} 

int Heap::LeftChild(int i) 
{ 
    int rval; 
    rval = ((2*i)+1); //leftchild is index times 2 plus 1 
    return rval; 
} 

void Heap::Heapify(int i) 
{ 
    int temp, l, r, heapify; 

    l = LeftChild(i); // get the left child 
    r = RightChild(i); // get the right child 

    if((l <= heapSize) && (data[l] > data[i])) 
    { 
     heapify = l; 
    { 
    else 
    { 
     heapfiy = i; 
    } 
    if((r <= heapSize) && (data[r] > data[heapify])) 
    { 
     heapify = r; 
    } 
    if(heapify != i) // one of the two child nodes has proved 
    {    // larger than Data[i], so interchange values 
     //swap parent with left child 
     temp = Data[i]; 
     Data[i] = Data[heapify]; 
     Data[heapify] = temp; 
     Heapify(heapify); 
    } 
} 

void Heap::BuildHeap() 
{ 
    // we do not have a heap 
    // we will make a heap 
    // by calling heapify starting at the lowest 
    // internal node in the heap 
    for(int i = heapsize; i >= 1; i--) 
    { 
     Heapify(i-1); 
    } 
} 

void Heap::insert() 
{ 
    int insert; 
    heapsize = (heapsize + 1); 
    //getting data from the user 
    cout<<"what data would you like to insert?"<<endl; 
    cin>>insert; 
    Data[heapsize] = insert; 
    BuildHeap(); //call BuildHeap on array 
    cout<<"done"<<endl; 
} 

void Heap::PrintHeap() 
{ 
    BuildHeap(); 
    for(int count = 0; count < (heapsize-1); count++) 
    { 
     cout<<Data[count];// print out every element in heap 
    } 
    cout<<endl<<endl; 
} 

void Heap::HeapSort() 
{ 
    BuildHeap(); 
    int temp; 
    // do this for every elem in heap: 
    for(int i = 0; i < heapsize; i++) 
    { 
     temp = Data[heapsize-1]; 
     Data[heapsize-1] = Data[0]; 
     Data[0] = temp; 
     heapsize--; 
     BuildHeap(); 
    } 
    PrintHeap(); 
} 

void Heap::ExtractMaximum() 
{ 
    BuildHeap(); 
    //assign last thing in heap to first thing in heap 
    Data[0] = Data[heapsize]; 
    heapsize --; // decrease heapsize by one 
    Heapify(0); // heapify from the top 
} 

int Heap::Maximum() 
{ 
    int Rval; 
    BuildHeap();// make sure we have a heap 
    Rval = Data[0]; 
    return Rval; // return top thing 
} 

//initialize the elements in the "Data" array 
void Heap::SetData(int x[]) 
{ 
    for(int i = 0; i <= (heapsize); i++) 
    { 
     Data[i] = x[i]; 
    } 
} 
+19

आहा! प्रयास के सबूत के साथ एक होमवर्क सवाल!+1 – vcsjones

+1

डी ओह, बहुत बहुत धन्यवाद! –

+0

@vcsjones: वास्तव में, दुख की बात है एक दुर्लभता। – ildjarn

उत्तर

8

आपका एल्गोरिदम काम करता है। समस्या कोड के लिए एल्गोरिदम के अनुवाद में है। आप के रूप में डाटा घोषित कहते हैं:

int Data[7]; 

और आप प्रारंभिक मान {0, 1, 2, 3, 4, 5, 6} से पॉप्युलेट।

#define LeftChild(i) ((i << 1) + 1) 
#define RightChild(i) ((i << 1) + 2) 

तो अपने समारोह BuildHeap() है, जो की तरह कुछ किया जाना चाहिए::

void Heap::BuildHeap() 
{ 
    for(int i = (7 >> 1); i >= 1; i--) // in general, replace 7 with 
             // (sizeof(Data)/sizeof(int)), presuming 
             // you have an array of int's. if not, 
             // replace int with the relevant data type 
    Heapify(i-1); 
} 

Heapify प्रक्रिया को नीचे दायें-सबसे उप पर शुरू हो जाएगा LeftChild(i) और RightChild(i) की परिभाषा यह मानकर की तरह कुछ होने के लिए पेड़ की जड़। इस मामले में, यह एरे इंडेक्स 2 है, जिसमें 5 के बाएं बच्चे हैं और 6 के दाहिने बच्चे हैं। Heapify सही ढंग से 2 और 6 का आदान-प्रदान करेंगे और Heapify(6) पर दोबारा कॉल करेंगे।

यहां पूरी चीज चारों ओर दौड़ सकती है!

      0 
        1   2 
       3  4 5  6 
      u n d e f i n e d s p a c e 

तो कॉल Heapify(6) कर्तव्यनिष्ठा Data[6] के मूल्यों Data[13] और Data[14] (सी ++ और सरणी सीमाओं प्रवर्तन की कमी, जावा के विपरीत के खतरों) के साथ तुलना करेंगे: वर्तमान में अपने पेड़ की तरह दिखता है। जाहिर है, बाद वाले दो मूल्य रैम में छोड़े गए किसी भी जंक हो सकते हैं। यहां एक समाधान, बदसूरत लेकिन एक काम करने वाला पैच, डेटा की घोषणा में 8 तत्व जोड़ना है और उन्हें सभी को सरणी के किसी भी तत्व से कम मूल्य में प्रारंभ करना है।

heapSize = (sizeof(Data)/sizeof(int)); 

फिर अगर वे पेड़ के वैध पत्तियां हैं केवल तुलना बच्चे नोड्स तर्क एकीकृत: बेहतर समाधान को अपनी कक्षा में एक heapSize चर में जोड़कर अपनी सरणी की लंबाई के बराबर सेट करने के लिए है। इस का एक कुशल कार्यान्वयन है:

void Heap::Heapify(int i) 
{ 
    int temp, l, r, heapify; 

    l = LeftChild(i); // get the left child 
    r = RightChild(i); // get the right child 

    if((l <= heapSize) && (Data[l] > Data[i])) 
     heapify = l; 
    else heapfiy = i; 
    if((r <= heapSize) && (Data[r] > Data[heapify])) 
     heapify = r; 
    if(heapify != i) // one of the two child nodes has proved 
        // larger than Data[i], so interchange values 
    { 
     //swap parent with left child 
     temp = Data[i]; 
     Data[i] = Data[heapify]; 
     Data[heapify] = temp; 

     Heapify(heapify); 
    } 
} 

तो संक्षेप में प्रस्तुत करने, समाधान सुनिश्चित करें कि बच्चे नोड्स के पेड़ के पत्ते वैध हैं, और आपके मुख्य कार्य की तरह कुछ होगा बनाने के लिए तर्क के रूप में जोड़ने के रूप में स्पष्ट है:

Heap heap; 

// initialize Data here  

heap.BuildHeap(); 

आशा है कि मदद करता है।

1

आपका कोड यहां लिखा गया है सही लगता है; लेकिन कुछ परीक्षण मामलों को लिखने की तरह कुछ भी नहीं है यह देखने के लिए कि यह कैसा प्रदर्शन करता है। 1, 2, 3, 4, और दर्जनों तत्वों के साथ एक ढेर के खिलाफ परीक्षण करना सुनिश्चित करें। (मैं जहां इस टुकड़े कम पड़ता आधार मामला होने की उम्मीद है - यह कैसे संभाल जब i छोटे ढेर पर कोई बच्चा नहीं ?. परीक्षण है करता है जल्दी में दिखाने के लिए चाहिए।)

इस टुकड़े के लिए कुछ छोटे सलाह:

if(Data[l] > Data[r]) 
{ 
    //swap parent with left child 
    temp = Data[i]; 
    Data[i] = Data[l]; 
    Data[l] = temp; 
    heapify = l; // index that was swapped 
} 
//if right is the bigger child 
else 
    { //swap parent with right child 
    temp = Data[i]; 
    Data[i] = Data[r]; 
    Data[r] = temp; 
    heapify = r; // index that was swapped 
} 

आप शायद if ब्लॉकों में केवल सूचकांक की स्थापना करके कुछ स्पष्टता हासिल कर सकता: पेड़ पर

if(Data[l] > Data[r]) { 
    swapme = l; 
} else { 
    swapme = r; 
} 

temp = Data[i]; 
Data[i] = Data[swapme]; 
Data[swapme] = temp; 
heapify = swapme; 
+0

मैंने इसे कुछ बार चलाया है, और यह काम नहीं करेगा। यह वास्तव में ढेर के लिए कुछ भी नहीं करता है। हालांकि मैं इसे कॉल करने के लिए एक अलग फ़ंक्शन का उपयोग कर रहा हूं, लेकिन वह सभी फ़ंक्शन सबसे कम आंतरिक नोड कहलाता है और फिर वहां से हेपफीइफ़ को कॉल करता है। मैं कल अपने प्रोफेसर से पूछूंगा, लेकिन मैं बस @ _ @ –

+1

@Chris नहीं समझता: क्या आप अपना प्रश्न अपनी पूर्ण श्रेणी परिभाषा के साथ अपडेट कर सकते हैं? समस्या कहीं और झूठ बोल सकती है, उदा। 'वाम चाइल्ड' या 'राइट चाइल्ड' के अर्थशास्त्र में, या जिस तरह से 'डेटा' घोषित किया गया है। – ildjarn

8

सं

 1 
    /\ 
    / \ 
/ \ 
    2  3 
/\ /\ 
6 7 4 5 

उत्पादन

 3 
    /\ 
    / \ 
/ \ 
    2  5 
/\ /\ 
6 7 4 1 

जो कई ढेर उल्लंघन नहीं किया जाना होने जा रहा है। (मैं यह सोचते हैं रहा है कि Data[l] और Data[r] शून्य से अनंत अगर इसी बच्चों मौजूद नहीं हैं। आप इस सुनिश्चित करने के लिए अतिरिक्त तर्क पड़ सकता है।)

क्या अपने कार्य करता है एक पेड़ है कि एक ढेर नहीं हो सकता है ठीक है लेकिन जिनके बाएं और दाएं उपट्री ढेर हैं। आपको प्रत्येक नोड पर, पोस्टऑर्डर में (यानी, मैं n से 1 से 0 तक) पर कॉल करने की आवश्यकता है ताकि जब मैं (i) को बुलाया जाता है तो मेरे बच्चे ढेर होते हैं।

+1

आपको पत्ते नोड्स के लिए कॉल करने की ज़रूरत नहीं है। –

4

आपका कोड अब सफलतापूर्वक एक ढेर बनाता है। केवल एक वैचारिक दोष था: बाकी एक-एक-एक इंडेक्सिंग त्रुटियां थीं। एक मौलिक त्रुटि BuildHeap में था: यदि आप था

for(int i = heapSize; i >= 1; i--) 
{ 
    Heapify(i-1); 
} 

इस जबकि होना चाहिए

for(int i = (heapSize/2); i >= 1; i--) 
{ 
    Heapify(i-1); 
} 

यह वास्तव में महत्वपूर्ण है, जैसा कि आप देख लेना चाहिए कि Heapify हमेशा एक पेड़ जड़ पर कहा जाता है, और (यह है वास्तव में अच्छा) आप आसानी से इंडेक्स ((हेपसाइज/2) - 1) में सरणी में अंतिम पेड़ की जड़ पा सकते हैं (यह सी ++ और जावा शैली के लिए है जहां पहली अनुक्रमणिका == 0) है। जिस तरह से यह अपने कोड पेड़ है, जो गलती से हुआ है के अंतिम पत्ती पर Heapify बुलाया लिखा गया था।

उसके अलावा, मैं ध्वज पर टिप्पणियां जोड़ीं बंद-एक करके त्रुटियों। मैंने उन्हें बाएं फ्लश रखा ताकि आप आसानी से उन्हें ढूंढ सकें। आशा है कि आपको एल्गोरिदम और डेटा संरचनाओं की एक सबब समझ मिल जाएगी! :-)

आपका हेडर फाइल:

#ifndef HEAP_H 
#define HEAP_H 
//Programmer: Christopher De Bow 
//Date: november 15, 2011 

class Heap 
{ 
private: 
    int Data [100]; 
    int Parent(int); 
    int RightChild(int); 
    int LeftChild(int); 
    void Heapify(int); 
    void BuildHeap(); 
// SO added heapSize 
    int heapSize; 

public: 
    Heap(); 
    void insert(); 
    void HeapSort(); 
    void ExtractMaximum(); 
    int Maximum(); 
    void PrintHeap(); 
    int heapsize; 
    void SetData(int[]); 
}; 

#endif 

आपका cpp फ़ाइल:

#include <iostream> 
#include "Heap.h" 
using namespace std; 
//Programmer: Christopher De Bow 
//Date: november 15, 2011 

Heap::Heap() 
{ 
    int init [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
    heapSize = 10; 
    SetData(init); 
} 

int Heap::Parent(int index) 
{ 
    int Rval; 
    if(index%2 == 0)// if the index is even 
    { 
     Rval = ((index-1)/2); 
    } 
    else// if the index is odd 
    { 
     Rval = (index/2); 
    } 
    return Rval; 
} 

int Heap::RightChild(int arrplace) 
{ 
    int ret; 
    ret = ((2*arrplace)+2); //rightchild is index times 2 plus 2 
    return ret; 
} 

int Heap::LeftChild(int i) 
{ 
    int rval; 
    rval = ((2*i)+1); //leftchild is index times 2 plus 1 
    return rval; 
} 

void Heap::Heapify(int i) 
{ 
    int temp, l, r, heapify; 

    l = LeftChild(i); // get the left child 
    r = RightChild(i); // get the right child 

// you have to compare the index to (heapSize - 1) because we are working 
// with C++ and the first array index is 0 : l and r are direct indices 
// into the array, so the maximum possible index is the heapSize'th 
// element, which is at heapSize-1. this was kind of nasty as it let the 
// heapify index get too large and led to a swap with memory beyond the 
// last element of the array (again, C++ doesn't enforce array boundaries 
// as Java does). 
    if((l <= (heapSize-1)) && (Data[l] > Data[i])) 
     heapify = l; 
    else 
     heapify = i; 
// you have to compare the index to (heapSize - 1) because we are working 
// with C++ and the first array index is 0 : l and r are direct indices 
// into the array, so the maximum possible index is the heapSize'th 
// element, which is at heapSize-1. this was kind of nasty as it let the 
// heapify index get too large and led to a swap with memory beyond the 
// last element of the array (again, C++ doesn't enforce array boundaries 
// as Java does). 
    if((r <= (heapSize-1)) && (Data[r] > Data[heapify])) 
     heapify = r; 
    if(heapify != i) // one of the two child nodes has proved 
    {    // larger than Data[i], so interchange values 
     //swap parent with left child 
     temp = Data[i]; 
     Data[i] = Data[heapify]; 
     Data[heapify] = temp; 
     Heapify(heapify); 
    } 
} 

void Heap::BuildHeap() 
{ 
    // we do not have a heap 
    // we will make a heap 
    // by calling heapify starting at the lowest 
    // internal node in the heap 
// i must be initialized to (heapsize/2), please see my 
// post for an explanation 
    for(int i = heapSize/2; i >= 1; i--) 
    { 
     Heapify(i-1); 
    } 
} 

void Heap::insert() 
{ 
    int insert; 
    heapSize = (heapSize + 1); 
    //getting data from the user 
    cout<<"what data would you like to insert?"<<endl; 
    cin>>insert; 
    Data[heapSize] = insert; 
    BuildHeap(); //call BuildHeap on array 
    cout<<"done"<<endl; 
} 

void Heap::PrintHeap() 
{ 
    BuildHeap(); 
// the array indices are from 0 through (heapSize-1), so 
// count must be less than _or equal to_ (heapSize-1). another 
// way of phrasing this (which i applied in this function) 
// is (count < heapSize). you'll get better boundary conditions 
// with practice. 
    for(int count = 0; count < heapSize; count++) 
    { 
// added an endl to the output for clarity 
     cout << Data[count] << endl;// print out every element in heap 
    } 
    cout<<endl<<endl; 
} 

void Heap::HeapSort() 
{ 
    BuildHeap(); 
    int temp; 
    // do this for every elem in heap: 
    for(int i = 0; i < heapSize; i++) 
    { 
     temp = Data[heapSize-1]; 
     Data[heapSize-1] = Data[0]; 
     Data[0] = temp; 
     heapSize--; 
     BuildHeap(); 
    } 
    PrintHeap(); 
} 

void Heap::ExtractMaximum() 
{ 
    BuildHeap(); 
    //assign last thing in heap to first thing in heap 
    Data[0] = Data[heapSize]; 
    heapSize--; // decrease heapSize by one 
    Heapify(0); // heapify from the top 
} 

int Heap::Maximum() 
{ 
    int Rval; 
    BuildHeap();// make sure we have a heap 
    Rval = Data[0]; 
    return Rval; // return top thing 
} 

//initialize the elements in the "Data" array 
void Heap::SetData(int x[]) 
{ 
// the array indices are from 0 through (heapSize-1), so 
// count must be less than _or equal to_ (heapSize-1). another 
// way of phrasing this (which i applied in this function) 
// is (i < heapSize). you'll get better boundary conditions 
// with practice. 
    for(int i = 0; i < heapSize; i++) 
    { 
     Data[i] = x[i]; 
    } 
} 

// basic confirmation function 
int main() 
{ 
    Heap heap; 
    heap.PrintHeap(); 

    return 0; 
} 
संबंधित मुद्दे