国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

數(shù)據(jù)結(jié)構(gòu)---------堆排序

2019-11-06 08:48:54
字體:
供稿:網(wǎng)友

    說到堆排序,它的思想來源于優(yōu)先隊(duì)列,我們首先來說一下什么是優(yōu)先隊(duì)列。

一、優(yōu)先隊(duì)列

1.優(yōu)先隊(duì)列的定義:優(yōu)先隊(duì)列是允許以下兩種操作的數(shù)據(jù)結(jié)構(gòu):Insert(插入)相當(dāng)于入隊(duì)、DeleteMin(刪除最小元)。

2.使用數(shù)據(jù)結(jié)構(gòu):相比于單鏈表和二叉排序樹的缺點(diǎn),我們使用二叉堆這種結(jié)構(gòu),它有兩個(gè)重要的性質(zhì)就是:

    結(jié)構(gòu)性——完全二叉樹    堆序行——小頂堆或大頂堆3.實(shí)現(xiàn):因?yàn)橥耆鏄溆幸?guī)律,我們使用數(shù)組實(shí)現(xiàn),對(duì)于數(shù)組中任一位置i上的元素,其左兒子為2*i,右兒子為 2*i+1,父親為  i/2,(下標(biāo)從1開始)。

4.思想:

插入:將一個(gè)元素X插入到堆中后,我們?cè)谙乱粋€(gè)位置創(chuàng)建一個(gè)空穴,如果X不破壞堆結(jié)構(gòu),那么Insert完成。否則,我們把該空穴的父親節(jié)點(diǎn)移動(dòng)到該空穴,直到X被放入到空穴為止。我們把這種操作稱為上濾。刪除最小元:刪除最小元后產(chǎn)生一個(gè)空穴,堆中最后一個(gè)元素X必須移動(dòng)到堆中的某個(gè)地方,如果X可以被放到空穴,那么DeleleMin完成,否則,將空穴較小的兒子移入空穴,直至X被移動(dòng)到正確的位置。我們把這種操作稱為下濾。5.實(shí)現(xiàn):

聲明:

#include <stdio.h>#include <stdlib.h>#define ElementType int/*優(yōu)先隊(duì)列數(shù)組實(shí)現(xiàn)*/typedef struct HeapStrcut	//堆結(jié)構(gòu){	int Capcity;	int Size;	ElementType *Elements;}*PRiorityQueue;PriorityQueue Initialize(int MaxElements);  //創(chuàng)建初始化優(yōu)先隊(duì)列void Insert(ElementType X, PriorityQueue H);//插入ElementType DeleteMin(PriorityQueue H);	    //刪除最小節(jié)點(diǎn)int IsEmpty(PriorityQueue H);		    //判斷優(yōu)先隊(duì)列是否為空int IsFull(PriorityQueue H);		    //判斷優(yōu)先隊(duì)列是否已滿實(shí)現(xiàn):

/*創(chuàng)建初始化優(yōu)先隊(duì)列小頂堆,最小元在根節(jié)點(diǎn)*/PriorityQueue Initialize(int MaxElements){	PriorityQueue H;	//申請(qǐng)優(yōu)先隊(duì)列結(jié)構(gòu)空間	H = (PriorityQueue)malloc(sizeof(struct HeapStrcut));	if(NULL == H)	{ 		printf("Out of space./n");		exit(-1);	}	//申請(qǐng)存儲(chǔ)數(shù)據(jù)數(shù)組Elements空間	H->Elements = (ElementType *)malloc(sizeof(ElementType)*MaxElements);	if (H->Elements == NULL)	{		printf("Out of space./n");		exit(-1);	}	//初始化優(yōu)先隊(duì)列	H->Capcity = MaxElements;	H->Size = 0;}/*插入,交換而實(shí)施的賦值語句為d+1*/void Insert(ElementType X, PriorityQueue H){	int i;	if(IsFull(H))	{ 		printf("The PriorityQueue is full./n");		exit(-1);	}		for (i = ++H->Size; H->Elements[i / 2] > X; i /= 2)		H->Elements[i] = H->Elements[i / 2];	H->Elements[i] = X;}//我的插入寫法,交換而實(shí)施的賦值語句為3dvoid Insert2(ElementType X, PriorityQueue H){	int i, tmp;	if (IsFull(H))	{		printf("The PriorityQueue is full./n");		exit(-1);	}	H->Elements[++H->Size] = X;	tmp = H->Elements[H->Size];	for (i = H->Size; i / 2 > 0; i /= 2)		if (H->Elements[i / 2] > H->Elements[i])			H->Elements[i] = H->Elements[i / 2];		else			break;	H->Elements[i] = tmp;}/*刪除最小節(jié)點(diǎn)*/ElementType DeleteMin(PriorityQueue H){	int i, child;	ElementType MinElement, LastElement;	if (IsEmpty(H))	{		printf("The PriorityQueue is empty./n");		exit(-1);	}	MinElement = H->Elements[1];	LastElement = H->Elements[H->Size--];	for (i = 1; i * 2 <= H->Size; i = child)	{		//查找較小的子節(jié)點(diǎn)		child = i * 2;		if (child != H->Size && H->Elements[child + 1] < H->Elements[child])			child++;		//下濾操作		if (LastElement > H->Elements[child])			H->Elements[i] = H->Elements[child];		else			break;	}	H->Elements[i] = LastElement;	return MinElement;}/*判斷優(yōu)先隊(duì)列是否為空*/int IsEmpty(PriorityQueue H){	return H->Size == 0;}/*判斷優(yōu)先隊(duì)列是否已滿*/int IsFull(PriorityQueue H){	return H->Size == H->Capcity;}/*顯示優(yōu)先隊(duì)列元素*/void show(PriorityQueue H){	int i;	for (i = 1; i <= H->Size; i++)		printf("%d/t", H->Elements[i]);	printf("/n");}int main(){	int max_elements, flag=1, choose, value;	//構(gòu)建優(yōu)先隊(duì)列	printf("開始構(gòu)建優(yōu)先隊(duì)列/n");	printf("請(qǐng)輸入優(yōu)先隊(duì)列大小:/n");	scanf("%d", &max_elements);	PriorityQueue H = Initialize(max_elements);		//優(yōu)先隊(duì)列操作	while (flag)	{		printf("請(qǐng)輸入操作,1.插入 2.刪除最小元 3.顯示優(yōu)先隊(duì)列元素./n");		scanf("%d", &choose);		switch (choose)		{		case 1:			printf("請(qǐng)輸入插入元素/n");			scanf("%d", &value);			Insert(value, H);			break;		case 2:			DeleteMin(H);			show(H);			break;		case 3:			show(H);			break;		default:			flag = 0;			break;		}	}    return 0;}

二、堆排序

1.思路:將要排序的數(shù)據(jù)構(gòu)建成小頂堆,交換根與最后節(jié)點(diǎn),下濾重新構(gòu)建堆。

2.實(shí)現(xiàn):

       數(shù)組實(shí)現(xiàn),下標(biāo)從0開始:

/*堆排序思路:堆排序分為構(gòu)建堆、刪除最值、調(diào)整堆即上濾下濾操作。方法:使用數(shù)組代替ADT(抽象數(shù)據(jù)類型)的方式實(shí)現(xiàn)初始堆數(shù)組下標(biāo)從零開始。總結(jié):時(shí)間復(fù)雜度為N*logN。*///上濾操作void PercDown(ElementType A[], int i, int N)	//i為父節(jié)點(diǎn)下標(biāo){	int replChild;		//下濾操作時(shí)用來與根節(jié)點(diǎn)交換的孩子節(jié)點(diǎn)下標(biāo)	ElementType tmp;	//一般利用交換進(jìn)行的排序都要有一個(gè)tmp變量	//每次開始都要取出最頂點(diǎn)下標(biāo),所以可以寫在for語句頭中作為初始條件	//遍歷的條件就是父節(jié)點(diǎn)還有孩子	//執(zhí)行完此次下濾操作后需要找到下次下濾操作的父節(jié)點(diǎn),所以我們也可以寫到for語句頭	for (tmp = A[i]; 2*i+1 < N; i = replChild)	//i = replChild是在語句體執(zhí)行之后執(zhí)行的	{		if (2 * i + 1 != N - 1 && A[2 * i + 1] < A[2 * i + 1 + 1])//若右孩子存在且右孩子大則將右孩子下濾			replChild = 2 * i + 1 + 1;		if (2 * i + 1 != N - 1 && A[2 * i + 1] > A[2 * i + 1 + 1])//若右孩子存在且右孩子小則將左孩子下濾			replChild = 2 * i + 1;		if(2 * i + 1 == N - 1)		//若右孩子不存在則將左孩子下濾				replChild = 2 * i + 1;		//書上方法		//replChild = 2*i+1;		//if (replChild != N - 1 && A[replChild + 1] > A[replChild])		//	replChild++;		//滿足孩子比父親數(shù)據(jù)大,將孩子數(shù)據(jù)賦值父親數(shù)據(jù),		//否則,不滿足堆結(jié)構(gòu),不需要下濾跳出循環(huán)		if (tmp < A[replChild])			A[i] = A[replChild];		else			break;	}	A[i] = tmp;}//堆排序void HeapSort(ElementType A[], int N){	int i, temp;;	for (i = N / 2; i >= 0; i--)		PercDown(A, i, N);	for (i = N - 1; i > 0; i--)	{	//交換根與最后的節(jié)點(diǎn)數(shù)據(jù)		temp = A[0];		A[0] = A[i];		A[i] = temp;		PercDown(A, 0, i);	}}

3.分析:堆排序的時(shí)間復(fù)雜度為O(longN),構(gòu)建N個(gè)數(shù)據(jù)的二叉堆需要O(N)時(shí)間,DeleteMin需要O(NlogN)時(shí)間。

              堆排序是一個(gè)穩(wěn)定的排序,無論起始的數(shù)據(jù)序列是如何的。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 新晃| 宾川县| 天水市| 杂多县| 贵德县| 登封市| 乌兰察布市| 探索| 南澳县| 维西| 开江县| 丹棱县| 日土县| 海丰县| 吉安市| 庆阳市| 光泽县| 富平县| 太湖县| 永嘉县| 南宫市| 当阳市| 兴国县| 郓城县| 赤壁市| 安达市| 瓦房店市| 连云港市| 洪泽县| 泽普县| 郁南县| 额济纳旗| 河西区| 邵武市| 房产| 襄城县| 大丰市| 阳城县| 聂荣县| 永寿县| 苍山县|