最近算法課作業是最小堆,於是便順便寫了這個代碼
最(大)小堆的性質:
(1)是一顆完全二叉樹,遵循完全二叉樹的所有性質。
(2)父節點的鍵值(大於)小於等於子節點的鍵值
(3)在堆排序中我們通常用的是最大堆,最小堆通常用在優先隊列中
代碼地址:https://github.com/whu-enjoy/Algorithms 倉庫的子文件夾heap中可以得到
https://github.com/whu-enjoy/Algorithms/tree/master/heap
/**************************************https://github.com/whu-enjoy/Algorithms/tree/master/heap****************************************
程序員 : enjoy5512
最後修改時間 : 2016年3月30日 17:09:08
函數說明 : 這個代碼用來測試最大堆的插入刪除排序等用法
******************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define Size 11
/*
函數說明 :
這個函數用於最大堆的上移操作
輸入參數 :
heap : 需要移動的堆
i : 需要移動的數在堆中的位置(1-n)
輸出參數 :
0
*/
int SiftUp(int heap[],int i)
{
int temp = 0;
//循環移動,i等於1則退出
for (;1 != i;i = i / 2)
{
//子節點大於父節點則上移,否則退出
if (heap[i - 1] > heap[(i - 2) / 2 ])
{
temp = heap[i - 1];
heap[i - 1] = heap[(i -2) / 2];
heap[(i -2) / 2] = temp;
}
else
{
break;
}
}
return 0;
}
/*
函數說明 :
這個函數用於最大堆的下移操作
輸入參數 :
heap : 需要移動的堆
i : 需要移動的數在堆中的位置(1-n)
n : 堆的大小
輸出參數 :
0
*/
int SiftDown(int heap[],int i,int n)
{
int temp = 0;
//循環移動,直到子節點大於堆的大小時退出
for (;2*i <= n;)
{
i = i * 2;
//尋找子節點中最大的子節點,作爲下移的對象
if ((i + 1 <= n) && (heap[i] > heap[i - 1]))
{
i = i + 1;
}
//若父節點比子節點小則下移,否則結束
if (heap[(i - 2) / 2] < heap[i - 1])
{
temp = heap[(i - 2) / 2];
heap[(i - 2) / 2] = heap[i - 1];
heap[i - 1] = temp;
}
else
{
break;
}
}
return 0;
}
/*
函數說明 :
這個函數用於最大堆的插入操作
輸入參數 :
oldheap : 原來的堆
n : 原來的堆的大小
newheap : 新的堆
x : 需要插入的數據
輸出參數 :
0
*/
int Insert(int oldheap[],int n,int newheap[],int x)
{
int i = 0;
//循環將原來的堆複製到新的堆
for(i = 0 ;i < n ;i++)
{
newheap[i] = oldheap[i];
}
newheap[n] = x; //將插入的值插入到新的堆的最後一個
SiftUp(newheap,n+1); //上移操作
return 0;
}
/*
函數說明 :
這個函數用於最大堆的刪除操作
輸入參數 :
oldheap : 原來的堆
n : 原來的堆的大小
newheap : 新的堆
i : 需要刪除的數據在堆中的位置
輸出參數 :
0
*/
int Delete(int oldheap[],int n,int newheap[],int i)
{
int j = 0;
int temp = 0;
//循環將原來的堆的前n-1個數據複製到新的堆
for (j = 0; j < n - 1; j++)
{
newheap[j] = oldheap[j];
}
temp = newheap[i - 1]; //保存堆要刪的元素
newheap[i - 1] = oldheap[n - 1]; //將要刪除的數據與最後一個元素交換位置
//如果刪除的數據比最後一個數據小,則上移,否則下移
if (newheap[i - 1] > temp)
{
SiftUp(newheap,i);
}
else
{
SiftDown(newheap,i,10);
}
oldheap[n - 1] = 0; //將原來的堆最後一個元素置爲0
return 0;
}
/*
函數說明 :
這個函數用於最大堆的刪除最大值操作
輸入參數 :
heap : 需要刪除元素的堆
n : 堆的大小
輸出參數 :
x : 堆的最大值
*/
int DeleteMax(int heap[],int n)
{
int x = 0;
x = heap[0];
Delete(heap,n,heap,1); //刪除第一個元素
return x;
}
/*
函數說明 :
這個函數用於最大堆的創建操作
輸入參數 :
heap : 需要創建的堆
n : 堆的大小
輸出參數 :
0
*/
int Makeheap(int heap[],int n)
{
int i = 0;
//遍歷所有節點的父節點,對每個遍歷的節點進行下移操作
for(i = n/2;i > 0;i--)
{
SiftDown(heap,i,n);
}
return 0;
}
/*
函數說明 :
這個函數用於最大堆的排序操作
輸入參數 :
heap : 需要排序的堆
n : 堆的大小
輸出參數 :
0
*/
int heapsort(int heap[],int n)
{
int i = 0;
int temp = 0;
Makeheap(heap,n); //先創建堆
//每次取出最大的元素放到數組的最後面
//然後每次對堆的第一個元素進行下移操作(範圍1-(i-1))
for(i = n; i > 1; i--)
{
temp = heap[0];
heap[0] = heap[i-1];
heap[i-1] = temp;
SiftDown(heap,1,i-1);
}
}
/*
函數說明 :
這個函數用於顯示堆,堆的最下層數據不得超過40,每個數據不得超過兩位數
否則格式將出現問題
輸入參數 :
heap : 需要顯示的堆
n : 堆的大小
輸出參數 :
0
*/
int Showheap(int heap[],int n)
{
int i = 0;
int j = 0;
int k = 0;
int count = 0;
int backspace = 0;
int high = 0;
high = log(n)/log(2) + 1; //求出堆的高度
for(k = 0; k < high - 1;k++)
{
count = pow(2,k); //每行打印的數據數
backspace = pow(2,high-k)-1; //每行兩個數據之間的空格數
for(j = 0;j < (backspace-1)/2;j++)
{
printf(" ");
}
for(i = 0; i < count; i++)
{
printf("%2d",heap[count+i-1]);
for(j = 0;j < backspace;j++)
{
printf(" ");
}
}
printf("\n");
}
i = pow(2,k) - 1;
printf("%d",heap[i]);
i++;
for(; i < n; i++) //打印最後一排數據
{
if(0 != heap[i])
{
printf(" %2d",heap[i]);
}
}
printf("\n");
return 0;
}
int main(void)
{
int heap[Size] = {4,3,12,10,11,13,7,30,17,26,0};
printf("數組原來的樣子:\n");
Showheap(heap,Size - 1);
printf("\n\n創建堆:\n");
Makeheap(heap,Size - 1);
Showheap(heap,Size - 1);
printf("\n\n第九個位置上的數變成20:\n");
heap[8] = 20;
SiftUp(heap,9);
Showheap(heap,Size - 1);
printf("\n\n第二個位置上的數變成2:\n");
heap[1] = 2;
SiftDown(heap,2,Size-1);
Showheap(heap,Size - 1);
printf("\n\n插入一個元素15:\n");
Insert(heap,Size - 1,heap,15);
Showheap(heap,Size);
printf("\n\n刪除第三個元素13:\n");
Delete(heap,Size,heap,3);
Showheap(heap,Size);
printf("\n\n刪除最大值:\n");
DeleteMax(heap,Size-1);
Showheap(heap,Size-1);
printf("\n\n堆排序:\n");
heapsort(heap,Size-2);
Showheap(heap,Size-2);
system("pause");
return 0;
}
最小堆跟最大堆實現方式差不多
/******************************************************************************
程序員 : enjoy5512
最後修改時間 : 2016年3月30日 20:36:18
函數說明 : 這個代碼用來測試最小堆的插入刪除排序等用法
******************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define Size 11
/*
函數說明 :
這個函數用於最小堆的上移操作
輸入參數 :
heap : 需要移動的堆
i : 需要移動的數在堆中的位置(1-n)
輸出參數 :
0
*/
int SiftUp(int heap[],int i)
{
int temp = 0;
//循環移動,i等於1則退出
for (;1 != i;i = i / 2)
{
//子節點小於父節點則上移,否則退出
if (heap[i - 1] < heap[(i - 2) / 2 ])
{
temp = heap[i - 1];
heap[i - 1] = heap[(i -2) / 2];
heap[(i -2) / 2] = temp;
}
else
{
break;
}
}
return 0;
}
/*
函數說明 :
這個函數用於最小堆的下移操作
輸入參數 :
heap : 需要移動的堆
i : 需要移動的數在堆中的位置(1-n)
n : 堆的大小
輸出參數 :
0
*/
int SiftDown(int heap[],int i,int n)
{
int temp = 0;
//循環移動,直到子節點序號大於堆的大小時退出
for (;2*i <= n;)
{
i = i * 2;
//尋找子節點中最小的子節點,作爲下移的對象
if ((i + 1 <= n) && (heap[i] < heap[i - 1]))
{
i = i + 1;
}
//若父節點比子節點大則下移,否則結束
if (heap[(i - 2) / 2] > heap[i - 1])
{
temp = heap[(i - 2) / 2];
heap[(i - 2) / 2] = heap[i - 1];
heap[i - 1] = temp;
}
else
{
break;
}
}
return 0;
}
/*
函數說明 :
這個函數用於最小堆的插入操作
輸入參數 :
oldheap : 原來的堆
n : 原來的堆的大小
newheap : 新的堆
x : 需要插入的數據
輸出參數 :
0
*/
int Insert(int oldheap[],int n,int newheap[],int x)
{
int i = 0;
//循環將原來的堆複製到新的堆
for(i = 0 ;i < n ;i++)
{
newheap[i] = oldheap[i];
}
newheap[n] = x; //將插入的值插入到新的堆的最後一個
SiftUp(newheap,n+1); //上移操作
return 0;
}
/*
函數說明 :
這個函數用於最小堆的刪除操作
輸入參數 :
oldheap : 原來的堆
n : 原來的堆的大小
newheap : 新的堆
i : 需要刪除的數據在堆中的位置
輸出參數 :
0
*/
int Delete(int oldheap[],int n,int newheap[],int i)
{
int j = 0;
int temp = 0;
//循環將原來的堆的前n-1個數據複製到新的堆
for (j = 0; j < n - 1; j++)
{
newheap[j] = oldheap[j];
}
temp = newheap[i - 1]; //保存堆要刪的元素
newheap[i - 1] = oldheap[n - 1]; //將要刪除的數據與最後一個元素交換位置
//如果刪除的數據比最後一個數據大,則上移,否則下移
if (newheap[i - 1] < temp)
{
SiftUp(newheap,i);
}
else
{
SiftDown(newheap,i,10);
}
oldheap[n - 1] = 4294967295; //將原來的堆最後一個元素置爲0
return 0;
}
/*
函數說明 :
這個函數用於最小堆的刪除最大值操作
輸入參數 :
heap : 需要刪除元素的堆
n : 堆的大小
輸出參數 :
x : 堆的最大值
*/
int DeleteMax(int heap[],int n)
{
int x = 0;
x = heap[0];
Delete(heap,n,heap,1); //刪除第一個元素
return x;
}
/*
函數說明 :
這個函數用於最小堆的創建操作
輸入參數 :
heap : 需要創建的堆
n : 堆的大小
輸出參數 :
0
*/
int Makeheap(int heap[],int n)
{
int i = 0;
//遍歷所有節點的父節點,對每個遍歷的節點進行下移操作
for(i = n/2;i > 0;i--)
{
SiftDown(heap,i,n);
}
return 0;
}
/*
函數說明 :
這個函數用於最小堆的排序操作
輸入參數 :
heap : 需要排序的堆
n : 堆的大小
輸出參數 :
0
*/
int heapsort(int heap[],int n)
{
int i = 0;
int temp = 0;
Makeheap(heap,n); //先創建堆
//每次取出最小的元素放到數組的最後面
//然後每次對堆的第一個元素進行下移操作(範圍1-(i-1))
for(i = n; i > 1; i--)
{
temp = heap[0];
heap[0] = heap[i-1];
heap[i-1] = temp;
SiftDown(heap,1,i-1);
}
}
/*
函數說明 :
這個函數用於顯示堆,堆的最下層數據不得超過40,每個數據不得超過兩位數
否則格式將出現問題
輸入參數 :
heap : 需要顯示的堆
n : 堆的大小
輸出參數 :
0
*/
int Showheap(int heap[],int n)
{
int i = 0;
int j = 0;
int k = 0;
int count = 0;
int backspace = 0;
int high = 0;
high = log(n)/log(2) + 1; //求出堆的高度
for(k = 0; k < high - 1;k++)
{
count = pow(2,k); //每行打印的數據數
backspace = pow(2,high-k)-1; //每行兩個數據之間的空格數
for(j = 0;j < (backspace-1)/2;j++)
{
printf(" ");
}
for(i = 0; i < count; i++)
{
printf("%2d",heap[count+i-1]);
for(j = 0;j < backspace;j++)
{
printf(" ");
}
}
printf("\n");
}
i = pow(2,k) - 1;
printf("%d",heap[i]);
i++;
for(; i < n; i++) //打印最後一排數據
{
if(4294967295 != heap[i])
{
printf(" %2d",heap[i]);
}
}
printf("\n");
return 0;
}
int main(void)
{
int heap[Size] = {20,17,9,10,11,4,5,3,7,5,4294967295};
printf("數組原來的樣子:\n");
Showheap(heap,Size - 1);
printf("\n\n創建堆:\n");
Makeheap(heap,Size - 1);
Showheap(heap,Size - 1);
printf("\n\n第九個位置上的數變成6:\n");
heap[8] = 6;
SiftUp(heap,9);
Showheap(heap,Size - 1);
printf("\n\n第二個位置上的數變成19:\n");
heap[1] = 19;
SiftDown(heap,2,Size-1);
Showheap(heap,Size - 1);
printf("\n\n插入一個元素4:\n");
Insert(heap,Size - 1,heap,4);
Showheap(heap,Size);
printf("\n\n刪除第三個元素4:\n");
Delete(heap,Size,heap,3);
Showheap(heap,Size);
printf("\n\n刪除最小值:\n");
DeleteMax(heap,Size-1);
Showheap(heap,Size-1);
printf("\n\n堆排序:\n");
heapsort(heap,Size-1);
Showheap(heap,Size-1);
system("pause");
return 0;
}