第二部分 排序
堆排序
堆(二叉堆):
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
思想:
1.从原始序列构建最大堆
2.将堆顶元素与堆的最后一个元素互换,删除最后一个元素,并调整当前堆为最大堆
3.循环执行(2)直到堆中只有一个元素
实现:
#include<iostream>
#include<vector>
using namespace std;
vector<int> build_maxheap(vector<int> heap, int size);
vector<int> max_heapify(vector<int> heap, int p, int heap_size);
int n;
int main()
{
vector<int> arr;
int temp = 1;
for (int i=10; i>0; i--)
arr.push_back(i);
for (int k=1; k<10; k++)
{
temp = temp * 2;
if (temp >= arr.size() )
{
n = temp - 1;
break;
}
}
vector<int> heap;
for (int i=0; i< n; i++)
heap.push_back(0);
for (int i=0; i< n; i++)
heap[i] = arr[i];
heap = build_maxheap(heap, arr.size());
int heap_size = arr.size();
for (int i=heap_size-1; i>0; i--)
{
int tempvalue = heap[i];
heap[i] = heap[0];
heap[0] = tempvalue;
heap_size = heap_size - 1;
heap = max_heapify(heap , 0, heap_size);
}
for (int i=0; i<arr.size(); i++)
{
cout << heap[i] <<" ";
}
cout <<endl;
return 0;
}
vector<int> build_maxheap(vector<int> heap, int size)
{
for (int i= (heap.size()+1)/2 -2; i>=0; i--)
heap = max_heapify( heap , i, size);
return heap;
}
vector<int> max_heapify(vector<int> heap, int p, int heap_size)
{
int largest;
int tempV;
int l = 2 * p + 1;
int r = 2 * p + 2;
if((l < heap_size) && (heap[l] > heap[p]))
largest = l;
else
largest = p;
if((r < heap_size) && (heap[r] > heap[largest]))
largest = r;
if (largest != p)
{
tempV = heap[p];
heap[p] = heap[largest];
heap[largest] = tempV;
heap = max_heapify(heap, largest, heap_size);
}
return heap;
}
优先级队列:
优先级队列可以用最大堆来实现
快速排序
思想:
在未排序序列中,重新安排次序,使得找到一个元素下标,使其前面的元素小于等于它,后面的元素大于等于它,然后再在前后两个子序列中递归调用此方法。
实现:
include<iostream>
#include<vector>
using namespace std;
vector<int> quick_sort(vector<int> arr, int start, int end);
int partition_q(vector<int> arr, int start, int end);
vector<int> partition_arr(vector<int> arr, int start, int end);
int q;
int main()
{
vector<int> arr;
for (int i=10; i>0; i--)
arr.push_back(i);
int start = 0;
int end = arr.size() - 1;
arr = quick_sort(arr, start, end);
for (int i=0; i<arr.size(); i++)
{
cout << arr[i] <<" ";
}
cout <<endl;
return 0;
}
vector<int> quick_sort(vector<int> arr, int start, int end)
{
if (start < end )
{
q = partition_q(arr,start,end);
arr = partition_arr(arr,start,end);
arr = quick_sort(arr, start, q-1);
arr = quick_sort(arr, q+1, end);
}
return arr;
}
int partition_q(vector<int> arr, int start, int end)
{
int x = arr[end];
int i = start - 1;
int temp;
int tempv;
for( int j = start; j<end; j++ )
{
if (arr[j] <= x)
{
i = i + 1;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
tempv = arr[i+1];
arr[i+1] = arr[end];
arr[end] = tempv;
int q = i + 1;
return q;
}
vector<int> partition_arr(vector<int> arr, int start, int end)
{
int x = arr[end];
int i = start - 1;
int temp;
int tempv;
for( int j = start; j<end; j++ )
{
if (arr[j] <= x)
{
i = i + 1;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
tempv = arr[i+1];
arr[i+1] = arr[end];
arr[end] = tempv;
int q = i + 1;
return arr;
}
线性时间排序
1.计数排序
应用范围: 整数
思想:
假设输入的线性表L的长度为n,L=L1,L2,..,Ln;线性表的元素属于有限偏序集S,|S|=k且k=O(n),S={S1,S2,..Sk};则计数排序可以描述如下:
1、扫描整个集合S,对每一个Si∈S,找到在线性表L中小于等于Si的元素的个数T(Si);
2、扫描整个线性表L,对L中的每一个元素Li,将Li放在输出线性表的第T(Li)个位置上,并将T(Li)减1。
2.基数排序(桶排序)
应用范围:整数,所有数位数相同
思想:
假设原来有一串数值如下所示:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
0
1 81
2 22
3 73 93 43
4 14
5 55 65
6
7
8 28
9 39
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
81, 22, 73, 93, 43, 14, 55, 65, 28, 39
接着再进行一次分配,这次是根据十位数来分配:
0
1 14
2 22 28
3 39
4 43
5 55
6 65
7 73
8 81
9 93
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93
这时候整个数列已经排序完毕