排序和搜索
1.所谓的内排序是指所有的数据已经读入内存。在内存中进行排序的算法;同时,内排序也一般假定所有用到的辅助空间可以直接存在于内存中。与之对应,另一类排序称为外排序,即内存中无法保存全部数据,需要进行磁盘访问,每次读入部分数据到内存进行排序。
合并排序:利用分而治之的思想,对两部分非别进行排序,排序完成后,在将各自排序好的两个部分合并还原成一个有序结构;算法的时间复杂度为O(nlog n)。
//合并函数
void Merge(int *_Array, int p, int q, int r) {// p:第0个;r:第n-1个数,q:第(r + p) / 2个数
int len1 = q - p + 1;
int len2 = r - q;
int *L = new int[len1 + 1];//用动态数组储存左边的数
int *R = new int[len2 + 1];//用动态数组储存右边的数
for (int i = 0; i < len1; i++) {// 把Array数组左边的数放入L数组
L[i] = _Array[p + i];
}
for (int j = 0; j < len2; j++) {// 把Array数组右边的数放入R数组
R[j] = _Array[q + 1 + j];
}
L[len1]=R[len2]=INT_MAX; //定义无穷大
int i = 0, j = 0;
for (int k = p; k <= r; k++) {
if (L[i] < R[j]) {//小的放左边,大的放右边
_Array[k] = L[i];
i++;
}
else {
_Array[k] = R[j];
j++;
}
}
}
// 归并排序
void MergeSort(int _Array[], int p, int r) {
if (p < r) {//p:第0个;r:第n-1个数。数组至少要有两个数据
int q;
q = (r + p) / 2;//拆分两组
MergeSort(_Array , p , q);//拆分第0个到第 (r + p) / 2个 ,即拆分左半部分
MergeSort(_Array , q+1 , r);//拆分第(r + p) / 2个到第r个 ,即拆分右半部分
Merge(_Array , p , q , r);//调用合并函数,从第0个到第n-1个排好
}
}
快速排序:随机选定一个元素作为轴值,利用该轴值将数据分为左右两个部分,左边元素都比轴值小,右边元素都比轴值大,但他们不是完全排序的,在此基础上,分别对左右两堆递归调用快速排序。算法的时间复杂度为O(nlog n),在最坏的情况下为O(n^2),额外空间复杂度O(log n)。
//快速排序
void quick_sort(int s[], int l, int r)
{
if (l < r)
{
//Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;
quick_sort(s, l, i - 1); // 递归调用
quick_sort(s, i + 1, r);
}
}
堆排序:每次将剩余的最大元素移动到数组的最右边。算法的时间复杂度为O(nlog n),空间复杂度O(1)。
//堆排序函数
void HeapSort(int a[],int length)
{
int temp;
BuildMaxHeap(a,length);
for (int i = length - 1; i >= 1; i--)
{
//交换根节点和数组的最后一个节点
temp = a[i];
a[i] = a[0];
a[0] = temp;
MaxHeapify(a, 0, 0, i-1);//维护从下标为i-1到0的子数组
}
}
桶排序和基数排序:不需要进行数据之间的两辆比较,但是需要事先知道数组的一些具体情况。桶排序适用于知道待排序数组大小范围的情况,其特性在于将数据根据其大小,放入合适的桶中,再依次从桶中取出,形成有序序列。基数排序,进行了K次桶排序。
void radixsort(int data[], int n) //基数排序
{
int d = maxbit(data, n);
int tmp[n];
int count[10]; //计数器
int i, j, k;
int radix = 1;
for(i = 1; i <= d; i++) //进行d次排序
{
for(j = 0; j < 10; j++)
count[j] = 0; //每次分配前清空计数器
for(j = 0; j < n; j++)
{
k = (data[j] / radix) % 10; //统计每个桶中的记录数
count[k]++;
}
for(j = 1; j < 10; j++)
count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
for(j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
{
k = (data[j] / radix) % 10;
tmp[count[k] - 1] = data[j];
count[k]--;
}
for(j = 0; j < n; j++) //将临时数组的内容复制到data中
data[j] = tmp[j];
radix = radix * 10;
}
}
快速选择算法:利用快速排序的思想,时间复杂度是O(n)。
二分查找:算法复杂度为O(logn)。
int binarySearch(int *array, int left, int right, int value){
if(left>right){
return -1;
}
int mid = right - (right - left)/2;
if(array[mid] == value){
return mid;
} else if(array[mid] < value){
return binarySearch(array,mid+1,right, value);
} else {
return binarySearch(array, left, mid-1, value);
}
}