1. 程式人生 > >堆建立、插入、刪除和排序

堆建立、插入、刪除和排序

1.建立堆

堆:n個元素序列{k1,k2,...,ki,...,kn},當且僅當滿足下列關係時稱之為堆:

(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4,...,n/2)

若將和此次序列對應的一維陣列(即以一維陣列作此序列的儲存結構)看成是一個完全二叉樹,則堆的含義表明,完全二叉樹中所有非終端結點的值均不大於(或不小於)其左、右孩子結點的值。由此,若序列{k1,k2,…,kn}是堆,則堆頂元素(或完全二叉樹的根)必為序列中n個元素的最小值(或最大值)。

一般用陣列來表示堆,i結點的父結點下標就為(i–1)/2。它的左右子結點下標分別為2*i+1和2*i+2。如第0個結點的左右子結點下標分別為1和2。

從無序序列建堆的過程就是一個反覆調整的過程。若將此序列看成是一個完全二叉樹,則最後一個非終端結點是第(n-2)/2個結點,由此調整過程只需從該結點開始,直到堆頂元素。

#ifndef _HEAP_H_
#define _HEAP_H_
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
#include<math.h>
#define MAXSIZE  10
typedef int DataType;

typedef struct heap
{
	DataType* arr;
	int size;
	int capacity;
}heap,*pheap;



//堆的初始化
void HeapInit(pheap hp)
{
	hp->size = 0;
	for (int i = 0; i < 10; i++)
	{
		hp->arr[i] = rand()%10;
		hp->size++;
	}
	hp->capacity = MAXSIZE;
}


//建堆
void CreatHeap(pheap hp)
{
	int i;
	for (i = (hp->size - 2) / 2; i >= 0; i--)
	{
		AdjustDown(hp,i);
	}
}


//向下調整(建堆)
void AdjustDown(pheap hp,int parent)
{
	assert(hp);
	//確定第一個非葉子結點的左孩子
	int lchild = 2 * parent + 1;
	while (lchild<hp->size)
	{//判斷第一個非葉子結點是否有右孩子並且比較左右孩子的大小,取小的
		if (lchild+1< hp->size&&hp->arr[lchild]>hp->arr[lchild+1])
			lchild++;
		if (hp->arr[lchild] >= hp->arr[parent])
			break;
		DataType temp = hp->arr[parent];
		hp->arr[parent] = hp->arr[lchild];
		hp->arr[lchild] = temp;
		parent = lchild;
		lchild = 2 * parent + 1;
	}
}

2.堆的插入

每次插入都是將先將新資料放在陣列最後,由於從這個新資料的父結點到根結點必然為一個有序的序列,現在的任務是將這個新資料插入到這個有序序列中——這就類似於直接插入排序中將一個數據併入到有序區間中。

//堆尾的插入
void HeapInsert(pheap hp, DataType data)
{
	assert(hp);
	if (hp->capacity == hp->size)
	{
		hp->arr = realloc(hp->arr, sizeof(DataType)*MAXSIZE * 2);
		hp->capacity = MAXSIZE * 2;
	}
	hp->arr[hp->size] = data;
	hp->size++;
	AdjustUp(hp);
}



//向上調整(插入)
void AdjustUp(pheap hp)
{//確定第一個非葉子結點
	int parent = (hp->size - 2) / 2;
	//確定第一個非葉子節點的左孩子
	int lchild = 2 * parent + 1;
	//一定要加上判斷條件lchild!=0;如果在只有兩個結點,且雙親結點
	//hp->arr[parent]>hp->arr[lchild]時,就會造成死迴圈。
	while (parent>=0&&lchild!=0)
	{//判斷插入結點位置
		if (lchild + 1 < hp->size)
			lchild++;
		if (hp->arr[lchild] >= hp->arr[parent])
			break;
		DataType temp = hp->arr[parent];
		hp->arr[parent] = hp->arr[lchild];
		hp->arr[lchild] = temp;
		lchild = parent;
		parent = (lchild - 1) / 2;
	}
}

3.堆頂的刪除

堆中每次都只能刪除堆頂元素。為了便於重建堆,實際的操作是將最後一個數據的值賦給根結點,然後再從根結點開始進行一次從上向下的調整。調整時先在左右子結點中找最小的,如果父結點比這個最小的子結點還小說明不需要調整了,反之將父結點和它交換後再考慮後面的結點。相當於根結點資料的“下沉”過程。

//堆頂的刪除
void Heapdel(pheap hp)
{
	assert(hp);
	if (!hp->size)
		return;
	DataType temp = hp->arr[0];
	hp->arr[0] = hp->arr[hp->size - 1];
	hp->arr[hp->size - 1] = temp;
	hp->size--;
	AdjustDown(hp,0);
}

void AdjustDown(pheap hp,int parent)
{
	assert(hp);
	//確定第一個非葉子結點的左孩子
	int lchild = 2 * parent + 1;
	while (lchild<hp->size)
	{//判斷第一個非葉子結點是否有右孩子並且比較左右孩子的大小,取小的
		if (lchild+1< hp->size&&hp->arr[lchild]>hp->arr[lchild+1])
			lchild++;
		if (hp->arr[lchild] >= hp->arr[parent])
			break;
		DataType temp = hp->arr[parent];
		hp->arr[parent] = hp->arr[lchild];
		hp->arr[lchild] = temp;
		parent = lchild;
		lchild = 2 * parent + 1;
	}
}

4.堆排序

若在輸出堆頂的最小值之後,使得剩餘n-1個元素的序列重建一個堆,則得到n個元素中的次小值。如此反覆執行,便能得到一個有序序列,這個過程稱之為堆排序。

輸出堆頂元素之後,以堆中最後一個元素替代之,此時根結點的左右子樹均為堆,則僅需進行一次從上到下的調整即可重建一個堆。


 堆排序演算法。
 形參heap為大頂堆時,實現的是由小到大;
 形參heap為小頂堆時,實現的是由大到小;
 
void HeapSort(pheap hp)
{
	int i;
	int temp;
	int num = hp->size;
	while (hp->size > 1)
	{
		for (i = hp->size - 1; i > 0; i--)
		{//交換堆頂元素
			temp = hp->arr[0];
			hp->arr[0] = hp->arr[i];
			hp->arr[i] = temp;
        //改變堆調整的資料個數
			hp->size--;
			AdjustDown(hp, 0);
		}
	}
     printf("堆排序:");
	for (int i = 0; i < num; i++)
	{
		printf("%d ", hp->arr[i]);
	}
}

5.堆測試

int main()
{
	pheap hp;
	hp = (pheap)malloc(sizeof(heap));
	if (!hp)
		return NULL;
	hp->arr= (DataType*)malloc(sizeof(DataType) * MAXSIZE);
	if (!hp->arr)
		return NULL;
	//用陣列來初始化堆
	HeapInit(hp);
	printf("用陣列來初始化堆:");
	//列印陣列
	for (int i = 0; i < hp->size; i++)
	{
		printf("%d ", hp->arr[i]);
	}
	printf("\n");
	//建立小頂堆並列印
	CreatHeap(hp);
	printf("建立小頂堆:");
	for (int i = 0; i < hp->size; i++)
	{
		printf("%d ", hp->arr[i]);
	}
	printf("\n");
	//堆插入資料 3
	HeapInsert(hp, 3);
	printf("堆插入資料 3:");
	for (int i = 0; i < hp->size; i++)
	{
		printf("%d ", hp->arr[i]);
	}
	printf("\n");
	//堆頂的刪除
	Heapdel(hp);
	printf("堆頂的刪除:");
	for (int i = 0; i < hp->size; i++)
	{
		printf("%d ", hp->arr[i]);
	}
	printf("\n");
	//堆排序
	HeapSort(hp);
	printf("\n");
	system("pause");
	return 0;
}

6.測試截圖

相關推薦

建立插入刪除排序

堆是一種完全二叉樹,有最小堆和最大堆之分,最小堆是指根節點的值一定小於左子樹和右子樹所有元素的值,最大堆則相反(當你從小到大排序時, 可以選擇最小堆反之,則選擇最大堆) 1.如何建立一個最小堆呢:由於堆是一個完全二叉樹,所以滿足以下關係

線性表的操作(完成表的建立插入刪除排序,銷燬,查詢 )

#include <stdio.h> #include <stdlib.h> #define Length 100 #define AddLength 50 //完成表的建立,插入,刪除,排序,銷燬,查詢 typedef struct { in

建立插入刪除排序

1.建立堆 堆:n個元素序列{k1,k2,...,ki,...,kn},當且僅當滿足下列關係時稱之為堆: (ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4,...,n/2)

二叉排序樹的操作(建立插入刪除查詢)

二叉排序樹的建立、插入、刪除和查詢 #include <stdio.h> #include <stdlib.h> typedef struct node { int key; struct node *lchild,*rchild

線性表---單鏈表(建立插入刪除排序測長列印輸出)

實現了動態建立一個學生資訊的連結串列,並能夠進行建立、插入、刪除、排序、測長和列印輸出等操作。 /*----------------------------------------------------------------- ////////關鍵部分

二叉查詢樹(二叉排序樹)建立插入刪除查詢-C語言

二叉查詢樹:或者是一顆空樹;或者是具有以下性質的二叉樹:(1)若它的左子樹不為空,則左子樹上所有結點的值都小於根結點的值;(2)若它的右子樹不為空,則右子樹所有結點的值均大於它的根結點的值;(3)左右子樹分別為二叉查詢樹; #include <std

二叉搜尋樹(BST)的建立插入查詢刪除

樹的結構體定義 struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; 插入 因為二叉搜

C++ 連結串列的基本操作:頭插入插入遍歷判斷連結串列是否為空清空求長度插入刪除逆置連結串列排序

// // main.cpp // List: // 連結串列的操作: // 1.頭插入 // 2.尾插入建立連結串列; // 3.遍歷連結串列; // 4.連結串列是否為空 // 5.清空連結串列 // 6.求連結串列的長度 // 7.

【資料結構樹表的查詢】二叉排序樹詳解程式碼(生成插入查詢最大值最小值刪除中序遍歷銷燬)

二叉排序樹(簡稱BST)又稱二叉查詢(搜尋)樹,其定義為:二叉排序樹或者是空樹,或者是滿足如下性質的二叉樹:       (1)若它的左子樹非空,則左子樹上所有記錄的值均小於根記錄的值;       (2)若它的右子樹非空,則右子樹上所有記錄的值均大於根記錄的值;     

二叉排序樹的建立插入刪除查詢4種遍歷 C++完整實現

#include<iostream> #include<string> #include<queue> using namespace std; typedef int KeyType; #define NUM 13 class Bi

C語言單鏈表的建立插入查詢刪除求長排序遍歷

1.定義連結串列節點 typedef struct Node { int data; struct Node *pNext; }NODE, *PNODE;2.連結串列的建立 PNODE crea

連結串列初解(一)——單鏈表的建立刪除插入測長排序逆置

由於考試需要,複習一下單鏈表的各種常見操作,直接上程式碼+註釋,需要的可以參考下哈~ Code: #include<iostream> using namespace std; typedef struct student { int data; str

程式設計實現順序儲存結構鏈式儲存結構線性表的建立查詢插入刪除等基本操作

#include <stdio.h> #include <stdlib.h> typedef struct LNode{ int data; //連結串列資料 struct LNode* next; //連結串列指標 }LNode,*L

C++ STL list的初始化新增遍歷插入刪除查詢排序釋放

list是C++標準模版庫(STL,Standard Template Library)中的部分內容。實際上,list容器就是一個雙向連結串列,可以高效地進行插入刪除元素。 使用list容器之前必須加上STL的list容器的標頭檔案:#include<list>;  

JAVA實現冒泡歸併希爾快速插入簡單選擇排序演算法

氣泡排序 public void bubbleSort(int []nums) { int exchange=nums.length-1; while(exchange!=0) { int bound=exchange; exchange=0; for(i

連結串列排序(冒泡選擇插入快排歸併希爾排序

參考http://www.cnblogs.com/TenosDoIt/p/3666585.html 插入排序(演算法中是直接交換節點,時間複雜度O(n^2),空間複雜度O(1)) 1 class Solution { 2 public: 3 ListNode *ins

靜態連結串列的建立插入刪除···

#include"stdio.h" #include"stdlib.h" #define MAXSIZE 1000 bool flag=true; typedef struct MyStruct { int data; int cur; }stlist[MAXSIZE]; //初始化連結

jquery DOM 建立插入刪除 複製替換包裹

1.建立元素節點: $(" ") 2.建立文字節點,與建立元素節點類似,可以直接把文字內容一併描述 $(“ 我是文字節點 ”) 3.建立屬性節點:與建立元素節點同樣的方式 $(“ 我是文字節點 ”) $(“ 動態建立DIV

連結串列的建立插入刪除逆序遍歷

#include <iostream> #include <stdlib.h> #include <stdio.h> using namespace std; typedef struct node{ int data; struct node * next

連結串列的建立查詢插入刪除

#include<iostream> #include<algorithm> #include<stdio.h> #include<malloc.h> #include<stack> using namespace