當前位置:首頁 » 操作系統 » 堆排序演算法

堆排序演算法

發布時間: 2022-01-16 10:14:14

㈠ 在快速排序、堆排序、歸並排序中,什麼排序是穩定的

歸並排序是穩定的排序演算法

歸並排序的穩定性分析:

歸並排序是把序列遞歸地分成短序列,遞歸出口是短序列只有1個元素或者2個序列,然後把各個有序的段序列合並成一個有序的長序列,不斷合並直到原序列全部排好序。

可以發現,在1個或2個元素時,1個元素不會交換,2個元素如果大小相等,沒有外部干擾,將不會破壞穩定性。

那麼,在短的有序序列合並的過程中,穩定性是沒有受到破壞的,合並過程中如果兩個當前元素相等時,把處在前面的序列的元素保存在結果序列的前面,這樣就保證了穩定性。所以,歸並排序也是穩定的排序演算法。

(1)堆排序演算法擴展閱讀:

演算法穩定性的判斷方法:

在常見的排序演算法中,堆排序、快速排序、希爾排序、直接選擇排序是不穩定的排序演算法,而基數排序、冒泡排序、直接插入排序、折半插入排序、歸並排序是穩定的排序演算法。

對於不穩定的排序演算法,只要舉出一個實例,即可說明它的不穩定性;而對於穩定的排序演算法,必須對演算法進行分析從而得到穩定的特性。

需要注意的是,排序演算法是否為穩定的是由具體演算法決定的,不穩定的演算法在某種條件下可以變為穩定的演算法,而穩定的演算法在某種條件下也可以變為不穩定的演算法。

比如,快速排序原本是不穩定的排序方法,但若待排序記錄中只有一組具有相同關鍵碼的記錄,而選擇的軸值恰好是這組相同關鍵碼中的一個,此時的快速排序就是穩定的。

參考資料來源:網路-排序演算法穩定性

㈡ 什麼是堆排序

【概念】堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序演算法,它是選擇排序的一種。可以利用數組的特點快速定位指定索引的元素。堆分為大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在數組的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。
【起源】
1991年的計算機先驅獎獲得者、斯坦福大學計算機科學系教授羅伯特·弗洛伊德(Robert W.Floyd)和威廉姆斯(J.Williams)在1964年共同發明了著名的堆排序演算法( Heap Sort )。
【簡介】
堆排序利用了大根堆(或小根堆)堆頂記錄的關鍵字最大(或最小)這一特徵,使得在當前無序區中選取最大(或最小)關鍵字的記錄變得簡單。
(1)用大根堆排序的基本思想
① 先將初始文件R[1..n]建成一個大根堆,此堆為初始的無序區
② 再將關鍵字最大的記錄R[1](即堆頂)和無序區的最後一個記錄R[n]交換,由此得到新的無序區R[1..n-1]和有序區R[n],且滿足R[1..n-1].keys≤R[n].key
③由於交換後新的根R[1]可能違反堆性質,故應將當前無序區R[1..n-1]調整為堆。然後再次將R[1..n-1]中關鍵字最大的記錄R[1]和該區間的最後一個記錄R[n-1]交換,由此得到新的無序區R[1..n-2]和有序區R[n-1..n],且仍滿足關系R[1..n-2].keys≤R[n-1..n].keys,同樣要將R[1..n-2]調整為堆。
……
直到無序區只有一個元素為止。
(2)大根堆排序演算法的基本操作:
①建堆,建堆是不斷調整堆的過程,從len/2處開始調整,一直到第一個節點,此處len是堆中元素的個數。建堆的過程是線性的過程,從len/2到0處一直調用調整堆的過程,相當於o(h1)+o(h2)…+o(hlen/2) 其中h表示節點的深度,len/2表示節點的個數,這是一個求和的過程,結果是線性的O(n)。
②調整堆:調整堆在構建堆的過程中會用到,而且在堆排序過程中也會用到。利用的思想是比較節點i和它的孩子節點left(i),right(i),選出三者最大(或者最小)者,如果最大(小)值不是節點i而是它的一個孩子節點,那邊交互節點i和該節點,然後再調用調整堆過程,這是一個遞歸的過程。調整堆的過程時間復雜度與堆的深度有關系,是lgn的操作,因為是沿著深度方向進行調整的。
③堆排序:堆排序是利用上面的兩個過程來進行的。首先是根據元素構建堆。然後將堆的根節點取出(一般是與最後一個節點進行交換),將前面len-1個節點繼續進行堆調整的過程,然後再將根節點取出,這樣一直到所有節點都取出。堆排序過程的時間復雜度是O(nlgn)。因為建堆的時間復雜度是O(n)(調用一次);調整堆的時間復雜度是lgn,調用了n-1次,所以堆排序的時間復雜度是O(nlgn)[2]
注意:
①只需做n-1趟排序,選出較大的n-1個關鍵字即可以使得文件遞增有序。
②用小根堆排序與利用大根堆類似,只不過其排序結果是遞減有序的。堆排序和直接選擇排序相反:在任何時刻堆排序中無序區總是在有序區之前,且有序區是在原向量的尾部由後往前逐步擴大至整個向量為止
【特點】
堆排序(HeapSort)是一樹形選擇排序。堆排序的特點是:在排序過程中,將R[l..n]看成是一棵完全二叉樹的順序存儲結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關系(參見二叉樹的順序存儲結構),在當前無序區中選擇關鍵字最大(或最小)的記錄
【演算法分析】
堆排序的時間,主要由建立初始堆和反復重建堆這兩部分的時間開銷構成,它們均是通過調用Heapify實現的。
平均性能:O(N*logN)。
其他性能:由於建初始堆所需的比較次數較多,所以堆排序不適宜於記錄數較少的文件。堆排序是就地排序,輔助空間為O(1)。它是不穩定的排序方法。(排序的穩定性是指如果在排序的序列中,存在前後相同的兩個元素的話,排序前 和排序後他們的相對位置不發生變化)。

㈢ 數據結構:堆排序的演算法實現

修改到如下形式即可
#include <stdio.h>
#include <iostream.h>
#define max 10

void headadjust(int num[],int head,int l)
{
//head為頂點的下標
for(int i = 2 * head;i < l;i *= 2)
{
if(head < l && num[i] < num[i+1])
++i;

if(num[head] > num[i])
break;

int flag = num[head];
num[head] = num[i];
num[i] = flag;
head = i;
}
}

void headsort(int num[])
{
for(int i = max/2; i >= 1; --i)
{
headadjust(num,i,max);
}

for(int j = max;j > 1; --j)
{
int temp=num[j];
num[j] = num[1];
num[1] = temp;
headadjust(num,1,j - 1);
}
}

void main()
{
int num[max+1]={0,39,45,12,89,45,67,38,45,72,88};
cout<<"排序前:";
for(int i = 1;i <= max;i++)
{
cout<<num[i]<<" ";
}
cout<<endl;
headsort(num);
cout<<"排序後:";
for(int j=1;j<=max;j++)
{
cout<<num[j]<<" ";
}
cout<<endl;
}

c語言 堆排序演算法升序排列N個數

#include<cstdio>

intarr[120000];
intmain()
{
intT,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(inti=1;i<=n;i++)
scanf("%d",&arr[i]);
sort(arr+1,arr+n+1);
for(inti=1;i<=n;i++)
printf("%d%c",arr[i],i==n?' ':'';
}
return0;
}

㈤ 急! 內部堆排序演算法的實現!!!包括大根堆的實現和小根堆的實現!!!要完整的!!!

1、 堆排序定義
n個關鍵字序列Kl,K2,…,Kn稱為堆,當且僅當該序列滿足如下性質(簡稱為堆性質):
(1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤ )

若將此序列所存儲的向量R[1..n]看做是一棵完全二叉樹的存儲結構,則堆實質上是滿足如下性質的完全二叉樹:樹中任一非葉結點的關鍵字均不大於(或不小於)其左右孩子(若存在)結點的關鍵字。
關鍵字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分別滿足堆性質(1)和(2),故它們均是堆,其對應的完全二叉樹分別如小根堆示例和大根堆示例所示。

2、大根堆和小根堆
根結點(亦稱為堆頂)的關鍵字是堆里所有結點關鍵字中最小者的堆稱為小根堆。
根結點(亦稱為堆頂)的關鍵字是堆里所有結點關鍵字中最大者,稱為大根堆。
注意:
①堆中任一子樹亦是堆。
②以上討論的堆實際上是二叉堆(Binary Heap),類似地可定義k叉堆。

3、堆排序特點
堆排序(HeapSort)是一樹形選擇排序。
堆排序的特點是:在排序過程中,將R[l..n]看成是一棵完全二叉樹的順序存儲結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關系,在當前無序區中選擇關鍵字最大(或最小)的記錄。

4、堆排序與直接插入排序的區別
直接選擇排序中,為了從R[1..n]中選出關鍵字最小的記錄,必須進行n-1次比較,然後在R[2..n]中選出關鍵字最小的記錄,又需要做n-2次比較。事實上,後面的n-2次比較中,有許多比較可能在前面的n-1次比較中已經做過,但由於前一趟排序時未保留這些比較結果,所以後一趟排序時又重復執行了這些比較操作。
堆排序可通過樹形結構保存部分比較結果,可減少比較次數。

5、堆排序
堆排序利用了大根堆(或小根堆)堆頂記錄的關鍵字最大(或最小)這一特徵,使得在當前無序區中選取最大(或最小)關鍵字的記錄變得簡單。

(1)用大根堆排序的基本思想
① 先將初始文件R[1..n]建成一個大根堆,此堆為初始的無序區
② 再將關鍵字最大的記錄R[1](即堆頂)和無序區的最後一個記錄R[n]交換,由此得到新的無序區R[1..n-1]和有序區R[n],且滿足R[1..n-1].keys≤R[n].key
③ 由於交換後新的根R[1]可能違反堆性質,故應將當前無序區R[1..n-1]調整為堆。然後再次將R[1..n-1]中關鍵字最大的記錄R[1]和該區間的最後一個記錄R[n-1]交換,由此得到新的無序區R[1..n-2]和有序區R[n-1..n],且仍滿足關系R[1..n-2].keys≤R[n-1..n].keys,同樣要將R[1..n-2]調整為堆。
……
直到無序區只有一個元素為止。

(2)大根堆排序演算法的基本操作:
① 初始化操作:將R[1..n]構造為初始堆;
② 每一趟排序的基本操作:將當前無序區的堆頂記錄R[1]和該區間的最後一個記錄交換,然後將新的無序區調整為堆(亦稱重建堆)。
注意:
①只需做n-1趟排序,選出較大的n-1個關鍵字即可以使得文件遞增有序。
②用小根堆排序與利用大根堆類似,只不過其排序結果是遞減有序的。堆排序和直接選擇排序相反:在任何時刻,堆排序中無序區總是在有序區之前,且有序區是在原向量的尾部由後往前逐步擴大至整個向量為止。

(3)堆排序的演算法:
void HeapSort(SeqIAst R)
{ //對R[1..n]進行堆排序,不妨用R[0]做暫存單元
int i;
BuildHeap(R); //將R[1-n]建成初始堆
for(i=n;i>1;i--){ //對當前無序區R[1..i]進行堆排序,共做n-1趟。
R[0]=R[1];R[1]=R[i];R[i]=R[0]; //將堆頂和堆中最後一個記錄交換
Heapify(R,1,i-1); //將R[1..i-1]重新調整為堆,僅有R[1]可能違反堆性質
} //endfor
} //HeapSort

(4) BuildHeap和Heapify函數的實現
因為構造初始堆必須使用到調整堆的操作,先討論Heapify的實現。
① Heapify函數思想方法
每趟排序開始前R[l..i]是以R[1]為根的堆,在R[1]與R[i]交換後,新的無序區R[1..i-1]中只有R[1]的值發生了變化,故除R[1]可能違反堆性質外,其餘任何結點為根的子樹均是堆。因此,當被調整區間是R[low..high]時,只須調整以R[low]為根的樹即可。
"篩選法"調整堆
R[low]的左、右子樹(若存在)均已是堆,這兩棵子樹的根R[2low]和R[2low+1]分別是各自子樹中關鍵字最大的結點。若R[low].key不小於這兩個孩子結點的關鍵字,則R[low]未違反堆性質,以R[low]為根的樹已是堆,無須調整;否則必須將R[low]和它的兩個孩子結點中關鍵字較大者進行交換,即R[low]與R[large](R[large].key=max(R[2low].key,R[2low+1].key))交換。交換後又可能使結點R[large]違反堆性質,同樣由於該結點的兩棵子樹(若存在)仍然是堆,故可重復上述的調整過程,對以R[large]為根的樹進行調整。此過程直至當前被調整的結點已滿足堆性質,或者該結點已是葉子為止。上述過程就象過篩子一樣,把較小的關鍵字逐層篩下去,而將較大的關鍵字逐層選上來。因此,有人將此方法稱為"篩選法"。
具體的演算法

②BuildHeap的實現
要將初始文件R[l..n]調整為一個大根堆,就必須將它所對應的完全二叉樹中以每一結點為根的子樹都調整為堆。
顯然只有一個結點的樹是堆,而在完全二叉樹中,所有序號 的結點都是葉子,因此以這些結點為根的子樹均已是堆。這樣,我們只需依次將以序號為 , -1,…,1的結點作為根的子樹都調整為堆即可。
具體演算法。

5、大根堆排序實例
對於關鍵字序列(42,13,24,91,23,16,05,88),在建堆過程中完全二叉樹及其存儲結構的變化情況參見。

6、 演算法分析
堆排序的時間,主要由建立初始堆和反復重建堆這兩部分的時間開銷構成,它們均是通過調用Heapify實現的。
堆排序的最壞時間復雜度為O(nlgn)。堆排序的平均性能較接近於最壞性能。
由於建初始堆所需的比較次數較多,所以堆排序不適宜於記錄數較少的文件。
堆排序是就地排序,輔助空間為O(1),
它是不穩定的排序方法。

㈥ 堆排序演算法的實現

#include<stdio.h>
#include<malloc.h>
#include<time.h>
#define LISTSIZE 100
#define MORESIZE 100
#define overflow -1
typedef struct
{
int data;
int fre;
}Cell;
typedef struct {
Cell *elem;
long int length;
unsigned long int count1;
unsigned long int count2;
long int listsize;
}SqList;
SqList L1;
clock_t start,end;
FILE *p,*w;
int main (void)
{
void assign(Cell *a,Cell *b);
int LT(int a,int b);
void HeapSort (SqList &H);
void HeapAdjust (SqList &H,int s , int m);
void exchange(Cell *a,Cell *b);

//讀入

int time=0;
while(time<4)
{
switch (time)
{
case 0:
p=fopen("data01.txt","r");
w=fopen("sorted01.txt","w");
break;
case 1:
p=fopen("data02.txt","r");
w=fopen("sorted02.txt","w");
break;
case 2:
p=fopen("data03.txt","r");
w=fopen("sorted03.txt","w");
break;
case 3:
p=fopen("data04.txt","r");
w=fopen("sorted04.txt","w");
break;
}

L1.count1=0;
L1.count2=0;

time++;
L1.elem=(Cell *)malloc((LISTSIZE+1)*sizeof(Cell));
L1.listsize=LISTSIZE;
L1.length=1;
Cell *newbase;
while(!feof(p))
{

if (L1.length>L1.listsize){
newbase=(Cell *)realloc(L1.elem,(L1.listsize+MORESIZE+1)*sizeof(Cell));
if (!newbase)
return overflow;
L1.elem=newbase;
L1.listsize+=MORESIZE;}
fscanf (p,"%d (%d)\n",&((L1.elem+L1.length)->data),&((L1.elem+L1.length)->fre));
L1.length++;
}
L1.length--;
printf ("listsize=%d length=%d\n",L1.listsize,L1.length);

//排序
start=clock();//開始計時
HeapSort(L1); //堆排序
end=clock(); //結束計時
printf ("Time: %lf\n",(double)(end-start)/CLOCKS_PER_SEC);//輸出時間
for (int i=1;i<L1.length+1;++i)
fprintf (w,"%d (%d)\n",(L1.elem+i)->data,(L1.elem+i)->fre);
fprintf (w,"比較次數%u,移動次數%u\n",L1.count1,L1.count2);
printf ("比較次數%u,移動次數%u\n",L1.count1,L1.count2);
fprintf (w,"Copyright Reserved,Cheng Xuntao,NWPU");
fclose(p);
fclose(w);
}

return 0;

}
int LT(int a,int b)//比較函數
{L1.count1++;<br/> if (a<b){<br/> <br/> return 1;}
else return 0;
}
void assign(Cell *a,Cell *b)//賦值函數
{
a->data=b->data;
a->fre=b->fre;
L1.count2++;
}
void exchange(Cell *a,Cell *b)//交換記錄
{
int temp;
temp=a->data;
a->data=b->data;
b->data=temp;
temp=a->fre;
a->fre=b->fre;
b->fre=temp;
L1.count2+=3; //+=3
}
void HeapAdjust (SqList &H,int s , int m)//調節其成為堆
{
Cell *rc;
rc=(Cell *)malloc(sizeof(Cell));
int j;
assign(rc,H.elem+s); //暫存
for (j=2*s;j<=m;j*=2){ //沿值較大的孩子節點向下篩選
if (j<m && LT((H.elem+j)->data,(H.elem+j+1)->data ))
j++; //j為值較大的記錄的下標
if (!LT(rc->data,(H.elem+j)->data))
break; //rc應插入在位置s上
assign((H.elem+s),(H.elem+j));
s=j;
}
assign((H.elem+s),rc); //插入
}//HeapAdjust
void HeapSort (SqList &H) //堆排序
{
int i;
for (i=H.length/2;i>0;--i) //把L.elem[1...H.length]建成堆
HeapAdjust(H,i,H.length);
for (i=H.length;i>1;--i)
{
exchange(H.elem+1,H.elem+i); //將堆頂記錄和當前未經排序的子序列L.elem[i...i]中最後一個記錄相互交換
HeapAdjust(H,1,i-1); //重新調整其為堆
}
}//HeapSort

㈦ 計算機的相關知識,堆排序是指什麼

排序就是相當於一個排序二叉樹,只是它是根節點的優先順序別大於任何兒子的優先順序別,這樣可以每次刪除根節點,然後調整整個堆。

㈧ 堆排序時間復雜度是什麼

堆排序時間復雜度,主要在每次選取最大數之後,重新建堆的過程以及初始化堆過程。

堆排序是指利用堆積樹這種數據結構所設計的一種排序演算法,它是選擇排序的一種。可以利用數組的特點快速定位指定索引的元素。

堆是一個優先順序隊列,對於大頂堆而言,堆頂元素的權值最大。將待排序的數組建堆,然後不斷地刪除堆頂元素,就實現了排序。

堆的操作

在堆的數據結構中,堆中的最大值總是位於根節點(在優先隊列中使用堆的話堆中的最小值位於根節點)。堆中定義以下幾種操作:

最大堆調整(Max Heapify):將堆的末端子節點作調整,使得子節點永遠小於父節點。

創建最大堆(Build Max Heap):將堆中的所有數據重新排序。

堆排序(HeapSort):移除位在第一個數據的根節點,並做最大堆調整的遞歸運算。

㈨ 堆排序是什麼

堆排序(HeapSort)是一樹形選擇排序。堆排序的特點是:在排序過程中,將R[l..n]看成是一棵完全二叉樹的順序存儲結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關系(參見二叉樹的順序存儲結構),在當前無序區中選擇關鍵字最大(或最小)的記錄
其過程為:
(1)用大根堆排序的基本思想

① 先將初始文件R[1..n]建成一個大根堆,此堆為初始的無序區


再將關鍵字最大的記錄R[1](即堆頂)和無序區的最後一個記錄R[n]交換,由此得到新的無序區R[1..n-1]和有序區R[n],且滿足R[1..n-1].keys≤R[n].key

③由於交換後新的根R[1]可能違反堆性質,故應將當前無序區R[1..n-1]調整為堆。然後再次將R[1..n-1]中關鍵字最大的記錄R[1]和該區間的最後一個記錄R[n-1]交換,由此得到新的無序區R[1..n-2]和有序區R[n-1..n],且仍滿足關系R[1..n-2].keys≤R[n-1..n].keys,同樣要將R[1..n-2]調整為堆。

……

直到無序區只有一個元素為止。

(2)大根堆排序演算法的基本操作:

① 初始化操作:將R[1..n]構造為初始堆;


每一趟排序的基本操作:將當前無序區的堆頂記錄R[1]和該區間的最後一個記錄交換,然後將新的無序區調整為堆(亦稱重建堆)。

注意:

①只需做n-1趟排序,選出較大的n-1個關鍵字即可以使得文件遞增有序。

②用小根堆排序與利用大根堆類似,只不過其排序結果是遞減有序的。堆排序和直接選擇排序相反:在任何時刻堆排序中無序區總是在有序區之前,且有序區是在原向量的尾部由後往前逐步擴大至整個向量為止

㈩ 關於堆排序的演算法

error LNK2019: 無法解析的外部符號 "void __cdecl MAX_HEAPIFY(int *,int,unsigned int)" (?MAX_HEAPIFY@@YAXPAHHI@Z),該符號在函數 "void __cdecl HEAPSORT(int *,unsigned int)" (?HEAPSORT@@YAXPAHI@Z) 中被引用

意思就是你那個函數沒有實現。

可以看到你的函數聲明和實現不一致:
void MAX_HEAPIFY(int *, int, size_t);
void MAX_HEAPIFY(int *arry, size_t i, size_t sz)
{}

參數類型不同,那就是不同的函數,C++的多態性。

修改聲明為:
void MAX_HEAPIFY(int *, size_t, size_t);

熱點內容
資料庫設計模板 發布:2024-11-15 00:47:25 瀏覽:825
編程的悟性 發布:2024-11-15 00:47:24 瀏覽:733
主流可編譯語言 發布:2024-11-15 00:42:23 瀏覽:729
excel緩存清除 發布:2024-11-15 00:39:53 瀏覽:486
機械鍵盤可編程 發布:2024-11-15 00:39:09 瀏覽:912
php判斷字元開頭 發布:2024-11-15 00:35:33 瀏覽:507
網易蘋果游戲怎麼轉移到安卓 發布:2024-11-15 00:07:52 瀏覽:270
win7php環境搭建 發布:2024-11-15 00:06:55 瀏覽:17
erpjava 發布:2024-11-14 23:52:23 瀏覽:253
電腦版地平線四怎麼連上伺服器 發布:2024-11-14 23:46:42 瀏覽:472