Binary Heap - Nattee · • Binary Heap – มีโครงสร างเป็น binary tree...
Transcript of Binary Heap - Nattee · • Binary Heap – มีโครงสร างเป็น binary tree...
© S. Prasitjutrakul 2013 14/10/57 1
Binary Heap
สมชาย ประสทิธิจ์ตูระกลู
© S. Prasitjutrakul 2013 14/10/57 2
priority_queue
push top,pop 5 3 99 5 4
© S. Prasitjutrakul 2013 14/10/57 3
สร้าง Priority Queue ด้วย Binary Heap
• push : O(log n)
• pop : O(log n)
• top : (1)
• ใช้โครงสร้างแบบ balanced binary tree
ราก (root)
ปมพ่อ/แม่ (parent)
ปมลูก (child)
ต้นไม้แบบทวิภาคได้ดุลที่มี n ปม สูง log2 n
สูง 3
© S. Prasitjutrakul 2013 14/10/57 4
ฮีปแบบทวิภาค
• Binary Heap
– มโีครงสรา้งเป็น binary tree แบบไดด้ลุ
• node เต็มทกุระดบั
• ระดบัลา่งสดุ เต็มจากซา้ยไปขวา
– ขอ้มลูของ parent node มคีา่มากกวา่ของลกู ๆ
15
50
2 10 18 20 3
21 4 2
30 5
รากเก็บค่ามากที่สุด
© S. Prasitjutrakul 2013 14/10/57 5
การสร้างฮีปแบบทวิภาคด้วยอาเรย์
0 1 2 3 4 5 6 7 8 9 10 11 12 13
mSize mData
15
50
2 10 18 20 3
21 4 2
30 5
50 30 5 15 21 4 2 2 10 18 20 3 12
• รากเก็บที่ index 0
• ลูกซ้ายของ node ที่ index k อยู่ที่ index 2k + 1
• ลูกขวาของ node ที่ index k อยู่ที่ index 2k + 2
• พ่อของ node ที่ index k อยู่ที่ index (k – 1) / 2
0
1 2
3 4 5 6
7 8 9 10 11
© S. Prasitjutrakul 2013 14/10/57 6
priority_queue : บริการ
priority_queue<T>
priority_queue<T, Comp>
bool empty();
size_t size();
const T& top();
void push(const T& e);
void pop();
priority_queue<T,Comp>&
operator=(priority_queue<T,Comp> rhs)
© S. Prasitjutrakul 2013 14/10/57 7
คลาส priority_queue template <typename T, typename Comp = std::less<T>>
class priority_queue {
protected:
T* mData;
size_t mCap;
size_t mSize;
Comp mLess;
public:
priority_queue(const Comp& c = Comp()) { ... }
priority_queue(const priority_queue<T,Comp>& a) { ... }
~priority_queue() { ... }
//------------- capacity function ----------
bool empty() const { ... }
size_t size() const { ... }
//----------------- access -----------------
const T& top() const { ... }
//----------------- modifier ---------------
void push(const T& e) { ... }
void pop() { ... }
};
mCap mData
3
mSize
4 99 23 33
mLess
© S. Prasitjutrakul 2013 14/10/57 8
constructor template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
T* mData;
size_t mCap;
size_t mSize;
Comp mLess;
public:
priority_queue(const Comp& c = Comp()) {
mCap = 1;
mData = new T[mcap]();
mSize = 0;
mLess = c;
}
priority_queue(const priority_queue<T,Comp>& a) {
mCap = a.mCap;
mData = new T[mcap]();
for (size_t i=0; i<a.mCap; i++) mData[i] = a.mData[i];
mSize = a.mSize;
mLess = a.mLess;
}
~priority_queue() {
delete [] mData;
}
mCap mData
0
mSize
1
mLess
© S. Prasitjutrakul 2013 14/10/57 9
constructor : initialization list template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
T* mData;
size_t mCap;
size_t mSize;
Comp mLess;
public:
priority_queue(const Comp& c = Comp()) :
mData(new T[1]()), mCap(1),
mSize(0), mLess(c) {
}
priority_queue(const priority_queue<T,Comp>& a) :
mData(new T[a.mCap]()), mCap(a.mCap),
mSize(a.mSize), mLess(a.mLess) {
for (size_t i=0; i<a.mCap; i++) mData[i] = a.mData[i];
}
~priority_queue() {
delete [] mData;
}
...
mCap mData
0
mSize
1
mLess
© S. Prasitjutrakul 2013 14/10/57 10
c++ : initialization list class A {
public:
A() {
a0 = 2; a1 = 3;
}
A(int x0, int x1) {
a0 = x0; a1 = x1;
}
protected:
int a0, a1;
};
class B : public A {
public:
B() { b = a0+a1; }
public:
int b;
};
int main() {
B b;
cout << b.b << endl; //5
}
class A {
public:
A() : a0(2), a1(3) {
}
A(int x0, int x1) :
a0(x0), a1(x1) {
}
protected:
int a0, a1;
};
class B : public A {
public:
B() : A(), b(a0+a1) {}
public:
int b;
};
int main() {
B b;
cout << b.b << endl; //5
}
© S. Prasitjutrakul 2013 14/10/57 11
c++ : initialization list
class A {
public:
A() : a0(2), a1(3) { }
A(int x0, int x1) :
a0(x0), a1(x1) { }
protected:
int a0, a1;
};
class B : public A {
public:
B() : A(), b(a0+a1) {}
public:
int b;
};
int main() {
B b;
cout << b.b << endl; //5
}
class A {
public:
A() : a0(2), a1(3) { }
A(int x0, int x1) :
a0(x0), a1(x1) { }
protected:
int a0, a1;
};
class B : public A {
public:
B() : A(4,5), b(a0+a1) {}
public:
int b;
};
int main() {
B b;
cout << b.b << endl; //9
}
© S. Prasitjutrakul 2013 14/10/57 12
c++ : initialization list class A {
public:
A() : a0(2), a1(3) { }
A(int x0, int x1) :
a0(x0), a1(x1) { }
protected:
int a0, a1;
};
class B : public A {
public:
B() {
A(4,5); // <-- สร้าง obj
b = a0 + a1; // 2+3
}
public:
int b;
};
int main() {
B b;
cout << b.b << endl; //5
}
class A {
public:
A() : a0(2), a1(3) { }
A(int x0, int x1) :
a0(x0), a1(x1) { }
protected:
int a0, a1;
};
class B : public A {
public:
B() : A(4,5), b(a0+a1) {}
public:
int b;
};
int main() {
B b;
cout << b.b << endl; //9
}
© S. Prasitjutrakul 2013 14/10/57 13
c++ : initialization list
• เร็วกว่า (ไม่ต้องตั้งค่า data members หลายครั้ง)
• เรียก non-default ctor ของ parent class ได ้
• เรียก non-default ctor ของ member ได ้
• ใช้ตั้งค่าให้ const และ reference members
class A {
const int a;
public:
A() : a(2) { }
A(int a) : a(a) { }
};
class A {
const int a;
public:
A() { a = 2; } //ผิด
};
class A {
int & a;
public:
A(int a) : a(a) { }
...
};
int main() {
int x = 3;
A a(x);
x = 2;
...
class A {
Foo f;
public:
A() : f(0) { }
A(int a) : f(a) { }
};
© S. Prasitjutrakul 2013 14/10/57 14
copy assignment operator : วิธีที่ 1 template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
T* mData;
size_t mCap;
size_t mSize;
Comp mLess;
public:
...
priority_queue<T,Comp>& operator=
(const priority_queue<T,Comp>& rhs) {
using std::swap;
priority_queue<T,Comp> temp(rhs);
swap(mSize, temp.mSize);
swap(mCap, temp.mCap );
swap(mData, temp.mData);
swap(mLess, temp.mLess);
return *this;
}
...
priority_queue<int> pq1, pq2;
for (int i=0; i<10; i++) pq1.push(1);
pq2 = pq1;
pass by reference
mCap mData
3
mSize
4 99 23 33
mLess
© S. Prasitjutrakul 2013 14/10/57 15
copy assignment operator : วิธีที่ 2 template <typename T, typename Comp = std::less<T> >
class queue {
protected:
T* mData;
size_t mCap;
size_t mSize;
Comp mLess;
public:
...
priority_queue<T,Comp>& operator=(priority_queue<T,Comp> rhs){
using std::swap;
swap(mSize, rhs.mSize);
swap(mCap, rhs.mCap );
swap(mData, rhs.mData);
swap(mLess, rhs.mLess);
return *this;
}
...
pass by value
priority_queue<int> pq1, pq2;
for (int i=0; i<10; i++) pq1.push(1);
pq2 = pq1;
// below is copy initialization
priority_queue<int> pq3 = pq1; // !!!
mCap mData
3
mSize
4 99 23 33
mLess
© S. Prasitjutrakul 2013 14/10/57 16
empty, size, top template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
T* mData;
size_t mCap;
size_t mSize;
Comp mLess;
public:
...
bool empty() const { // (1)
return mSize == 0;
}
size_t size() const { // (1)
return mSize;
}
const T& top() { // (1)
return mData[0];
}
...
mCap mData
3
mSize
4 99 23 33
mLess
© S. Prasitjutrakul 2013 14/10/57 17
push( e ) : เพิ่มข้อมูล
• น า e ไปตอ่เป็นใบถัดไป (เพิม่ทา้ยในอาเรย)์
• สลับ e กบัปมพอ่ จนกวา่ e จะไมม่ากกวา่พอ่
fixUp( 5 ) 13
12 1
2 12
0 1 2 3 4 5 6
mSize mData
13 12 1 2 12 16 5
16
6
16
16
ต าแหน่งของ ตวัทีอ่าจผดิกฎ
© S. Prasitjutrakul 2013 14/10/57 18
push( e ) template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
...
void fixUp(size_t c) {
T tmp = mData[c];
while (c > 0) {
size_t p = c / 2;
if ( mLess(tmp, mData[p]) ) break; // tmp < mData[p]
mData[c] = mData[p];
c = p;
}
mData[c] = tmp;
}
public:
void push(const T& element) {
if (mSize+1 > mCap) expand(mCap*2);
mData[mSize] = element;
mSize++;
fixUp(mSize-1);
}
© S. Prasitjutrakul 2013 14/10/57 19
priority_queue : less comparator template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
...
void fixUp(size_t c) {
T tmp = mData[c];
while (c > 0) {
size_t p = (c-1) / 2;
if ( mLess(tmp, mData[p]) ) break;
mData[c] = mData[p];
c = p;
}
mData[c] = tmp;
}
public:
void push(const T& element) {
if (mSize+1 > mCap) expand(mCap*2);
mData[mSize] = element;
mSize++;
fixUp(mSize-1);
}
namespace std {
template <class T> struct less : binary_function <T,T,bool> {
bool operator() (const T& x, const T& y) const {
return x < y;
}
};
...
© S. Prasitjutrakul 2013 14/10/57 20
priority_queue : less comparator
priority_queue<int, std::less<int>> pq1;
priority_queue<int, std::greater<int>> pq2;
priority_queue<int, CompFunc> pq3(myGreater);
priority_queue<int, CompFunc>
pq4( [](int x, int y){ return x > y; } ); // lambda
for (int i=0; i<10; i++) {
pq1.push(i);
pq2.push(i);
pq3.push(i);
pq4.push(i);
}
cout << pq1.top() << endl; // 9
cout << pq2.top() << endl; // 0
cout << pq3.top() << endl; // 0
cout << pq4.top() << endl; // 0
typedef bool(*CompFunc)(int, int);
bool myGreater(int a,int b) {
return a > b;
}
© S. Prasitjutrakul 2013 14/10/57 21
push( e ) : อาเรย์เต็มก็ขยาย template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
...
void expand(size_t capacity) {
T *arr = new T[capacity]();
for (size_t i = 0;i < mSize;i++) arr[i] = mData[i];
delete [] mData;
mData = arr; mCap = capacity;
}
...
public:
void push(const T& element) {
if (mSize+1 > mCap) expand(mCap*2);
mData[mSize] = element;
mSize++;
fixUp(mSize-1);
}
© S. Prasitjutrakul 2013 14/10/57 22
pop( ) : ลบตัวมากสุด
• เก็บรากไวเ้ป็นค าตอบ
• ยา้ยขอ้มลูทีใ่บลา่งขวาสดุ มาเก็บทีร่าก
• สลับขอ้มลูทีร่ากลงมา จนกวา่พอ่จะไมน่อ้ยกวา่ลกู
fixDown( 0 )
13
1 2 11
0 1 2 3 4 5 6
mSize mData
15 13 9 2 11 1 6 1 5
ต าแหน่งของ ตวัทีอ่าจผดิกฎ
9
15 1
1
1
© S. Prasitjutrakul 2013 14/10/57 23
pop( e ) : ลบตัวมากสุด template <typename T, typename Comp = std::less<T> >
class priority_queue {
protected:
...
void fixDown(size_t p) {
T tmp = mData[p];
size_t c;
while ((c = 2*p + 1) < mSize) {
if (c+1 < mSize && mLess(mData[c],mData[c+1])) c++;
if ( mLess(mData[c],tmp) ) break;
mData[p] = mData[c];
p = c;
}
mData[p] = tmp;
}
public:
void pop() {
mData[0] = mData[mSize-1];
mSize--;
fixDown(0);
}
© S. Prasitjutrakul 2013 14/10/57 24
เวลาการท างาน
• top : O(1)
• push : fixUp = O(h) = O(log n)
• pop : fixDown = O(h) = O(log n)
มีข้อมูล n ตัว สูง log2 n
© S. Prasitjutrakul 2013 14/10/57 25
priority_queue(T a[], int n, const Comp& c = Comp() ) :
mData(new T[n]()), mCap(n), mSize(0), mLess(c) {
for (int i=0; i<n; i++) push(a[i]);
}
4
1 3
6
การสร้างฮีปแบบทวิภาคด้วยการค่อย ๆ เพิ่ม
1 1
3
3
1 4
3
1
4
1 3
6
4 3
1
6
4 3
1 8
8
6 3
1 4
8
6 3
1 4 10
10
6 8
1 4 3 11
10
6 8
1 4 3
11
6 10
1 4 3 8
log2 1 + log2 2 + log2 3 +...+ log2 n < log2 n! = O(n log n)
log2 1 log2 2 log2 3
log2 4 log2 5
log2 6 log2 7
© S. Prasitjutrakul 2013 14/10/57 26
การสร้างฮีปแบบทวิภาคด้วยการค่อย ๆ ปรับ
1 25 12 10 11 27 9 1 20 25 21 7 19
0 1 2 3 4 5 6 7 8 9 10 11
25
12 10
11 27 9 1
20 25 21 7 19
19
9
25
11
19
10
27
21
12
27
25
priority_queue(T a[], int n, const Comp& c = Comp() ) :
mData(new T[n]()), mCap(n), mSize(n), mLess(c) {
for (int i=0; i<n; i++) mData[i] = a[i];
for (int i=mSize/2-1; i>=0; i--) fixDown(i);
}
© S. Prasitjutrakul 2013 14/10/57 27
การสร้างฮีปแบบทวิภาคด้วยการค่อย ๆ ปรับ
0
2
h
h k
k
k
สูง จ านวนต้น
4 1
3 2
2 4
1 8
0 16
k 2h – k
h
fixdown ในต้นไม้สูง k เกิดการสลับข้อมูลไม่เกิน k ครั้ง
0
2
h
h k
k
k
0
2 2
h
h k
k
k
0
2 2h k
k
k
= 2h+1 = O(n)
2
© S. Prasitjutrakul 2013 14/10/57 28
ฮีปมากสุด / ฮีปน้อยสุด (Max/Min Heap)
• ฮีปมากสุด
– ข้อมูลของ parent node มีค่ามากกว่าของลูก ๆ
• ฮีปน้อยสุด
– ข้อมูลของ parent node มีค่าน้อยกว่าของลูก ๆ
50
1 25
21 3
1
50 3
25 21
max heap min heap