堆建立、插入、刪除和排序
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