基於佇列和雜湊的種子填充演算法
阿新 • • 發佈:2019-01-08
繼 https://blog.csdn.net/u013749051/article/details/84553642 之後,
我又對種子填充演算法進行了改進,主要利用了雜湊的思想,以空間換時間,把這個演算法的速度再次優化了。
這次的優化效果非常好,填充大面積區域稍有卡頓。
下面是效果圖:
核心程式碼如下:雖然看起來很多,但是相同的內容很多,邏輯清晰。
void fillArea(int x, int y)
{
COLORREF color = getpixel(x, y); //獲取替換顏色
COLORREF paintColor = getfillcolor (); //獲取填充顏色
const int maxWidth = 640;
const int maxHeight = 480;
char filled[maxWidth * maxHeight] = {0}; //散列表, 雜湊函式 h(key) = key.x + key.y * maxWidth
Queue queue;
queue.push(x, y);
while (!queue.isEmpty())
{
Node* node = queue.pop();
if (node->x < 0 || node- >x >= maxWidth || node->y < 0 || node->y >= maxHeight)
{
delete node;
continue; //限制邊界
}
//後繼
int xT = node->x; int yT = node->y - 1;
int xB = node->x; int yB = node->y + 1;
int xL = node->x - 1; int yL = node->y;
int xR = node->x + 1; int yR = node->y;
COLORREF colorT = getpixel(xT, yT);
COLORREF colorB = getpixel(xB, yB);
COLORREF colorL = getpixel(xL, yL);
COLORREF colorR = getpixel(xR, yR);
int keyT = xT + yT * maxWidth;
int keyB = xB + yB * maxWidth;
int keyL = xL + yL * maxWidth;
int keyR = xR + yR * maxWidth;
if (colorT != paintColor && colorT == color && filled[keyT] != 1)
{
queue.push(xT, yT);
filled[keyT] = 1;
}
if (colorB != paintColor && colorB == color && filled[keyB] != 1)
{
queue.push(xB, yB);
filled[keyB] = 1;
}
if (colorL != paintColor && colorL == color && filled[keyL] != 1)
{
queue.push(xL, yL);
filled[keyL] = 1;
}
if (colorR != paintColor && colorR == color && filled[keyR] != 1)
{
queue.push(xR, yR);
filled[keyR] = 1;
}
//消已
putpixel(node->x, node->y, paintColor);
delete node;
}
}
程式碼解釋:
類似於樹的層序遍佈,這裡利用了一個 佇列結構
。
開始時,將種子點
壓入。
每當填充並刪除一個種子時,將其周圍的沒有填充的點作為 新的種子
壓入佇列中。
佇列結構是我自己寫的,如下:
struct Node
{
Node* next;
int x;
int y;
Node()
{
x = 0;
y = 0;
next = 0;
}
Node(int x, int y)
{
this->x = x;
this->y = y;
this->next = 0;
}
};
struct Queue
{
Node* head;
Node* tail;
Queue()
{
head = tail = new Node;
}
void push(int x, int y)
{
tail->next = new Node(x, y);
tail = tail->next;
}
Node* pop()
{
if (!isEmpty())
{
Node* temp = head->next;
head->next = head->next->next;
if (head->next == 0)
{
tail = head;
}
return temp;
}
return 0;
}
bool isEmpty()
{
return head == tail;
}
};
有同學可能對完整程式碼感興趣。我也順便附上吧。
這個程式引用了一個簡單的圖形庫 easyx
大家可以百度去官網下載。
#include <iostream>
#include <graphics.h>
using namespace std;
//佇列
struct Node
{
Node* next;
int x;
int y;
Node()
{
x = 0;
y = 0;
next = 0;
}
Node(int x, int y)
{
this->x = x;
this->y = y;
this->next = 0;
}
};
struct Queue
{
Node* head;
Node* tail;
Queue()
{
head = tail = new Node;
}
void push(int x, int y)
{
tail->next = new Node(x, y);
tail = tail->next;
}
Node* pop()
{
if (!isEmpty())
{
Node* temp = head->next;
head->next = head->next->next;
if (head->next == 0)
{
tail = head;
}
return temp;
}
return 0;
}
bool isEmpty()
{
return head == tail;
}
};
void fillArea(int x, int y)
{
COLORREF color = getpixel(x, y); //獲取替換顏色
COLORREF paintColor = getfillcolor(); //獲取填充顏色
const int maxWidth = 640;
const int maxHeight = 480;
char filled[maxWidth * maxHeight] = {0}; //散列表, 雜湊函式 h(key) = key.x + key.y * maxWidth
Queue queue;
queue.push(x, y);
while (!queue.isEmpty())
{
Node* node = queue.pop();
if (node->x < 0 || node->x >= maxWidth || node->y < 0 || node->y >= maxHeight)
{
delete node;
continue; //限制邊界
}
//後繼
int xT = node->x; int yT = node->y - 1;
int xB = node->x; int yB = node->y + 1;
int xL = node->x - 1; int yL = node->y;
int xR = node->x + 1; int yR = node->y;
COLORREF colorT = getpixel(xT, yT);
COLORREF colorB = getpixel(xB, yB);
COLORREF colorL = getpixel(xL, yL);
COLORREF colorR = getpixel(xR, yR);
int keyT = xT + yT * maxWidth;
int keyB = xB + yB * maxWidth;
int keyL = xL + yL * maxWidth;
int keyR = xR + yR * maxWidth;
if (colorT != paintColor && colorT == color && filled[keyT] != 1)
{
queue.push(xT, yT);
filled[keyT] = 1;
}
if (colorB != paintColor && colorB == color && filled[keyB] != 1)
{
queue.push(xB, yB);
filled[keyB] = 1;
}
if (colorL != paintColor && colorL == color && filled[keyL] != 1)
{
queue.push(xL, yL);
filled[keyL] = 1;
}
if (colorR != paintColor && colorR == color && filled[keyR] != 1)
{
queue.push(xR, yR);
filled[keyR] = 1;
}
//消已
putpixel(node->x, node->y, paintColor);
delete node;
}
}
int main()
{
initgraph(640, 480, 1);
setfillcolor(0xffffff);
fillrectangle(0, 0, 640, 480);
bool isDown = false;
MOUSEMSG msg;
int lastX;
int lastY;
while (true)
{
BeginBatchDraw();
while (MouseHit())
{
msg = GetMouseMsg();
if (msg.uMsg == WM_LBUTTONDOWN)
{
isDown = true;
lastX = msg.x;
lastY = msg.y;
}
if (msg.uMsg == WM_LBUTTONUP)
{
isDown = false;
}
if (isDown)
{
setcolor(0xff0000);
line(lastX, lastY, msg.x, msg.y);
lastX = msg.x;
lastY = msg.y;
}
if (msg.uMsg == WM_RBUTTONDOWN)
{
setfillcolor(0x0000ff);
fillArea(msg.x, msg.y);
}
}
EndBatchDraw();
Sleep(50);
}
system("pause");
closegraph();
}