ディレクトリ
- バブルソート
- 直接挿入ソート
- 単純な選択ソート
- シェルソート
- マージソート
- ヒープソート
- クイックソート
- カウンティングソート
- バケットソート
- 基数ソート
バブルソート
基本的な考え方は次のとおりです。キーワード比較二十から二隣接する記録、為替逆順場合
バブルソートの最良の場合の時間複雑\(O(N)\) 、最悪の場合、\(O(N ^ 2) \)
1の改善:そこに明らかに何の旅ではありません交換が発生した場合、フラグは、設定されている((=内のフラグをfalseに)\)\説明並べ替えが完了しています、
2の改良:[OK]をこの位置にヘッドからのマーカーダウン、次のトラバースの最後の位置を記録します
第二に、直接挿入ソート
あなたは、それによって、表1の番号で注文した新しいレコードを取得し、テーブルのソート順にレコードを持っています
時間の複雑さもある(O(^ N-2)\)\、およびバブルソートのパフォーマンスよりも選択的に優れています
第三に、簡単な選択ソート
ニッケル(Ni \)\からのキーワードとの比較、(NI + 1 \)\記録最小のキーレコードを選択し、第1及び第(I(1 \当量I \ \当量のN)\ )の交換を記録
同じバブルソートが、\(O(^ N-2)\) 、単にわずかに良いバブルソートよりもパフォーマンスをソート
第四に、ヒルソート
サブシーケンス(要素「デルタ」組成物によって分離)に分割される配列の要素の全体の最初の行は、放電増分を低減、さらに続いて、直接挿入ソートしました
全体の順序(増分十分に小さい)の配列に基本的な要素であるとタイミング、(1単位)直接挿入ソートのすべての要素。その時間複雑である(O(\ {N-FRAC。3} ^ {2})\)\、より良いの直接挿入ソートより\(O(N ^ 2) \)
第五に、マージソート
これは、最初の配列が含まれていることを想定(N- \)\レコード、と見なすことができる\(N- \)順序付けられたサブシーケンス、長さの各サブシーケンス\(1 \) 、次いで二十から二ギブをマージ\(\ lceil \ FRAC {N-2}} {\ rceil \) (以上\(\ FRAC {n}は{ 2} \) 最小の整数の長さ)である\(2 \)または\(1 \)配列を命じその後、二十から二マージ、...
、の長さになるまで繰り返します\(N- \)順序付けられたシーケンスになるまで、この順序付けメソッドが呼び出された\(2 \)パスのマージソート。
時間の複雑さはある\(O(nlogn)\) 、空間的複雑度は、\(O(N + logN個)\) 、非再帰的マージ場合、回避されたときに再帰の深さ\(logN個\)スタックスペース
空間的複雑です\(O(n)は、\)
第六に、ヒープソート
ヒープは、以下の特性を有する完全二分木である:各ノードの値が大きいAトップスタックと呼ばれる、左右の子ノードの値以上であり、各ノードまたは値未満またはその左の子ノードの値に等しいと呼ばれます小さなヒープトップ。
基本的な考え方は、ある方法は、ソート・ヒープソート・ヒープの使用であります:
順序付けられたシーケンスは、大きな山の頂に構成することができる。このとき、ルートノードの最大値がシーケンス全体のスタックの最上位である。それは除去する(スタックアレー交換要素の最後の要素は、実際にこの時間の終わりさでありますmax)は、残りの(N-1 \)\スタックに再構成シーケンス、これが与える(\ N-)\二値要素。
だから、もう一度実行し、の順序付けられたシーケンスを得ることができるようになります。
時間の複雑さはある(O(nlogn)\)\、より良いバブルよりも、単純に、直接に\(O(N ^ 2) \)
七、クイックソート
それぞれすばやくソートし、この方法は、すべてのデータの他の部分よりもデータの全ての部分が小さくなるように前記2つの別個の部分に分類されるデータ2つの部分をトリップデータを順序付けることによって、全体のソート処理であることができます再帰的に、全体のデータを達成するために、順序付けられたシーケンスになります。時間の複雑さがある\(O(nlogn)\)
注:上記(7 \)\種は比較的、次のよう命じている\(3 \)種を、非ソート比較され、理論的に到達することができます\(O(N)\)を、より高速な比較ソートよりも、これは3(\ \)種は、すべてのバックグラウンドでの役割、またはちょうど反対を再生するために自分のアプリケーションを持っています。
八、カウンティングソート
カウント配列決定は、安定ソートアルゴリズムです。追加のアレイ使用カウント配列\(C \)まず、\(I \)要素は、ソートされた配列であることがある\(A \)値に等しい\(I \)の要素の数。アレイは、その後で\(C \)に\(A \)最初の正しい位置に要素に。
次のようにアルゴリズムのステップは以下のとおりです。
最大と最小の要素を見つけるためにソートする配列
アレイ内の各値の統計\(I \)の要素の数が配列に現れる\(C \)の\(I \)キー
(からのすべての累積カウント)C \(\位置で\(1 \)の要素で始まる、先行添加のそれぞれ)
逆標的配列満たす:各要素を\(I \)最初の新しい配列内の\(C(I)\)項目置くする各要素\(C(I)\)減算\(1 \)
カウント用アレイので\(C \)の範囲(最大値と最小値をソートする配列に等しいプラスの差に応じてソートされる配列内のデータの長さ\(1 \)データカウント配列決定を行います)、範囲は非常に大きな配列は、時間と多くのメモリを必要とします。
九、バケットソート
またはソートボックスをソートする、いわゆるバケツは、それがソートアルゴリズムで、原理はバケットの限られた数の配列に割り当てられます。各個別のバケット、その後、ソートされた(それは再使用または他のソートアルゴリズムすることが可能である再帰的にソートソートバケツを継続して使用)
バケットは、ソート、次の手順で行わ:
空のバケツなどの量的配列を設定します。
シリアル検索、および対応するバケットにアイテムを一つずつ配置します。(ハッシュ)
各バケットについては、空のソートではありません。
家から空のバケットと、再度プロジェクトに元のシリアルではありません。
テン、基数ソート
基数ソート比較型が非整数ソートアルゴリズムであり、原理は、ビットの整数は、各のビット数を比較した、異なる数により切断されます。整数は、特定のフォーマット(例えば、名前、日付など)浮動小数点文字列を表現することができるので、基数ソートは、整数のみのために使用されません。
それが実装されている:すべての値は、均一なビット長の同じ数、先行ゼロを持つ桁短い数の(正の整数)を比較します。その後、最低のスタートから、一度にソート。これが完了すると、シリーズは、順序付けられたシーケンスとなったビットの最上位に低いものからソートされています。
基数ソート方法を使用LSD(最下位デジタル)またはMSD(最上位デジタル)することができ、LSDは、左端のキーから始めて、逆に右端のキー、およびMSDから順にソートされています。
#include<iostream>
using namespace std;
void swap1(int *left, int *right)
{
int temp = *left;
*left = *right;
*right = temp;
}
void swap2(int &left, int &right)
{
int temp = left;
left = right;
right = left;
}
void swap3(int &left, int &right)
{
if (&left != &right)
{
left ^= right;
right ^= left;
left ^= right;
}
}
/*****************************************************************/
/* 冒泡排序时间复杂度最好的情况为O(n),最坏的情况是O(n^2)
* 基本思想是:两两比较相邻记录的关键字,如果反序则交换 */
void BubbleSort1(int arr[], int num)
{
int i, j;
for (i = 0; i < num; i++)
{
for (j = 1; j < num - i; j++)
{
if (arr[j - 1] > arr[j])
swap1(&arr[j - 1], &arr[j]);
}
}
}
// 改进思路:设置标志位,明显如果有一趟没有发生交换(flag = flase),说明排序已经完成.
void BubbleSort2(int arr[], int num)
{
int k = num;
int j;
bool flag = true;
while (flag)
{
flag = false;
for (j = 1; j < k; j++)
{
if (arr[j - 1] > arr[j])
{
swap1(&arr[j - 1], &arr[j]);
flag = true;
}
}
k--;
}
}
//改进思路:记录一轮下来标记的最后位置,下次从头部遍历到这个位置就Ok
void BubbleSort3(int arr[], int num)
{
int k, j;
int flag = num;
while (flag > 0)
{
k = flag;
flag = 0;
for (j = 1; j < k; j++)
{
if (arr[j - 1] > arr[j])
{
swap1(&arr[j - 1], &arr[j]);
flag = j;
}
}
}
}
/*************************************************************************/
/**************************************************************************/
/*插入排序: 将一个记录插入到已经排好序的有序表中, 从而得到一个新的,记录数增1的有序表
* 时间复杂度也为O(n^2), 比冒泡法和选择排序的性能要更好一些 */
void InsertionSort(int arr[], int num)
{
int temp;
int i, j;
for (i = 1; i < num; i++)
{
temp = arr[i];
for (j = i; j > 0 && arr[j - 1] > temp; j--)
arr[j] = arr[j - 1];
arr[j] = temp;
}
}
/****************************************************************************/
/*希尔排序:先将整个待排元素序列分割成若干子序列(由相隔某个“增量”的元素组成的)分别进行
直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,
再对全体元素进行一次直接插入排序(增量为1)。其时间复杂度为O(n^3/2),要好于直接插入排序的O(n^2) */
void ShellSort(int *arr, int N)
{
int i, j, increment;
int tmp;
for (increment = N / 2; increment > 0; increment /= 2)
{
for (i = increment; i < N; i++)
{
tmp = arr[i];
for (j = i; j >= increment; j -= increment)
{
if (arr[j - increment] > tmp)
arr[j] = arr[j - increment];
else
break;
}
arr[j] = tmp;
}
}
}
/**************************************************************************/
/* 简单选择排序(simple selection sort) 就是通过n-i次关键字之间的比较,从n-i+1
* 个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换之
* 尽管与冒泡排序同为O(n^2),但简单选择排序的性能要略优于冒泡排序 */
void SelectSort(int arr[], int num)
{
int i, j, Mindex;
for (i = 0; i < num; i++)
{
Mindex = i;
for (j = i + 1; j < num; j++)
{
if (arr[j] < arr[Mindex])
Mindex = j;
}
swap1(&arr[i], &arr[Mindex]);
}
}
/********************************************************************************/
/*假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后
* 两两归并,得到(不小于n/2的最小整数)个长度为2或1的有序子序列,再两两归并,...
* 如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序
* 时间复杂度为O(nlogn),空间复杂度为O(n+logn),如果非递归实现归并,则避免了递归时深度为logn的栈空间
* 空间复杂度为O(n) */
/*lpos is the start of left half, rpos is the start of right half*/
void merge(int a[], int tmp_array[], int lpos, int rpos, int rightn)
{
int i, leftn, num_elements, tmpos;
leftn = rpos - 1;
tmpos = lpos;
num_elements = rightn - lpos + 1;
/*main loop*/
while (lpos <= leftn && rpos <= rightn)
if (a[lpos] <= a[rpos])
tmp_array[tmpos++] = a[lpos++];
else
tmp_array[tmpos++] = a[rpos++];
while (lpos <= leftn) /*copy rest of the first part*/
tmp_array[tmpos++] = a[lpos++];
while (rpos <= rightn) /*copy rest of the second part*/
tmp_array[tmpos++] = a[rpos++];
/*copy array back*/
for (i = 0; i < num_elements; i++, rightn--)
a[rightn] = tmp_array[rightn];
}
void msort(int a[], int tmp_array[], int left, int right)
{
int center;
if (left < right)
{
center = (right + left) / 2;
msort(a, tmp_array, left, center);
msort(a, tmp_array, center + 1, right);
merge(a, tmp_array, left, center + 1, right);
}
}
void merge_sort(int a[], int n)
{
int *tmp_array;
tmp_array = (int *)malloc(n * sizeof(int));
if (tmp_array != NULL)
{
msort(a, tmp_array, 0, n - 1);
free(tmp_array);
}
else
printf("No space for tmp array!\n");
}
/************************************************************************************/
/* 堆是具有下列性质的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;
* 或者每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆*/
/*堆排序就是利用堆进行排序的方法.基本思想是:将待排序的序列构造成一个大顶堆.此时,整个序列的最大值就是堆顶
* 的根结点.将它移走(其实就是将其与堆数组的末尾元素交换, 此时末尾元素就是最大值),然后将剩余的n-1个序列重新
* 构造成一个堆,这样就会得到n个元素的次大值.如此反复执行,便能得到一个有序序列了
*/
/* 时间复杂度为 O(nlogn),好于冒泡,简单选择,直接插入的O(n^2) */
// 构造大顶堆
#define leftChild(i) (2*(i) + 1)
void percDown(int *arr, int i, int N)
{
int tmp, child;
for (tmp = arr[i]; leftChild(i) < N; i = child)
{
child = leftChild(i);
if (child != N - 1 && arr[child + 1] > arr[child])
child++;
if (arr[child] > tmp)
arr[i] = arr[child];
else
break;
}
arr[i] = tmp;
}
void HeapSort(int *arr, int N)
{
int i;
for (i = N / 2; i >= 0; i--)
percDown(arr, i, N);
for (i = N - 1; i > 0; i--)
{
swap1(&arr[0], &arr[i]);
percDown(arr, 0, i);
}
}
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
/*****************计数排序*******************************/
void CountSort(int *arr, int num)
{
int mindata = arr[0];
int maxdata = arr[0];
for (int i = 1; i < num; i++)
{
if (arr[i] > maxdata)
maxdata = arr[i];
if (arr[i] < mindata)
mindata = arr[i];
}
int size = maxdata - mindata + 1;
//申请空间并初始化为0
int *pCount = (int *)malloc(sizeof(int) * size);
memset(pCount, 0, sizeof(int)*size);
//记录排序计数,每出现一次在对应位置加1
for (int i = 0; i < num; i++)
++pCount[arr[i]-mindata];
//确定不比该位置大的数据个数
for (int i = 1; i < size; i++)
pCount[i] += pCount[i - 1]; //加上前一个的计数
int *pSort = (int *)malloc(sizeof(int) * num);
memset((char*)pSort, 0, sizeof(int) * num);
//从末尾开始拷贝是为了重复数据首先出现的排在前面,即稳定排序
for (int i = num - 1; i >= 0; i--)
{
//包含自己需要减1,重复数据循环回来也需要减1
--pCount[arr[i]-mindata];
pSort[pCount[arr[i]-mindata]] = arr[i];
}
//拷贝到原数组
for (int i = 0; i < num; i++)
arr[i] = pSort[i];
free(pCount);
free(pSort);
}
/*****************桶排序*****************************/
struct Node
{
int key_;
struct Node *next_;
Node(int key)
{
key_ = key;
next_ = NULL;
}
};
#define bucket_size 10 //与数组元素个数相等
void buck_sort(int arr[], int num)
{
Node *bucket_table[bucket_size];
memset(bucket_table, 0, sizeof(bucket_table));
//建立每一个头节点,头节点的key保存当前桶的数据量
for (int i = 0; i < bucket_size; i++)
bucket_table[i] = new Node(0);
int maxValue = arr[0];
for (int i = 1; i < num; i++)
{
if (arr[i] > maxValue)
maxValue = arr[i];
}
for (int j = 0; j < num; j++)
{
Node *ptr = new Node(arr[j]);//其余节点的key保存数据
//映射函数计算桶号
// index = (value * number_of_elements) / (maxvalue + 1)
int index = (arr[j] * bucket_size) / (maxValue + 1);
Node *head = bucket_table[index];
//该桶还没有数据
if (head->key_ == 0)
{
bucket_table[index]->next_ = ptr;
(bucket_table[index]->key_)++;
}
else
{
//找到合适的位置插入
while (head->next_ != NULL && head->next_->key_ <= ptr->key_)
head = head->next_;
ptr->next_ = head->next_;
head->next_ = ptr;
(bucket_table[index]->key_)++;
}
}
//将桶中的数据拷贝回原数组
int m, n;
for (m = 0, n = 0; n < num && m < bucket_size; m++, n++)
{
Node *ptr = bucket_table[m]->next_;
while (ptr != NULL)
{
arr[n] = ptr->key_;
ptr = ptr->next_;
n++;
}
n--;
}
//释放分配的动态空间
for (m = 0; m < bucket_size; m++)
{
Node *ptr = bucket_table[m];
Node *tmp = NULL;
while (ptr != NULL)
{
tmp = ptr->next_;
delete ptr;
ptr = tmp;
}
}
}
/****************************************************/
/******************** 基数排序LSD*********************/
void base_sort_ISD(int *arr, int num)
{
Node *buck[10]; // 创建一个链表数组
Node *tail[10]; //保存每条链表尾节点指针集合,
//这样插入buck数组时就不用每次遍历到末尾
int i, MaxValue, kth, high, low;
Node *ptr;
for(MaxValue = arr[0], i = 1; i < num; i++)
MaxValue = max(MaxValue, arr[i]);
memset(buck, 0, sizeof(buck));
memset(tail, 0, sizeof(buck));
for(low = 1; high = low * 10, low < MaxValue; low *= 10)
{
//只要没排好序就一直排序
for(i = 0; i < num; i++)
{
//往桶里放
kth = (arr[i] % high) / low;//取出数据的某一位,作为桶的索引
ptr = new Node(arr[i]); //创建新节点
//接到末尾
if (buck[kth] != NULL)
{
tail[kth]->next_ = ptr;
tail[kth] = ptr;
}
else
{
buck[kth] = ptr;
tail[kth] = ptr;
}
}
//把桶中的数据放回数组中(同条链表是从头到尾)
for (kth = 0, i = 0; kth < num; i++)
{
while (buck[i] != NULL)
{
arr[kth++] = buck[i]->key_;
ptr = buck[i];
buck[i] = buck[i]->next_;
delete ptr;
}
}
memset(tail, 0, sizeof(buck));
}
}
/**************************************************************/
int main(void)
{
int arr1[] = {10, 15, 11, 20, 15, 18, 19, 12, 14, 17};
int size1 = sizeof(arr1) / sizeof(arr1[0]);
CountSort(arr1, size1);
for (int i = 0; i < size1; i++)
printf("%d ", arr1[i]);
printf("\n");
int arr2[] = {54, 8, 216, 512, 27, 729, 0, 1, 343, 125};
int size2 = sizeof(arr2) / sizeof(arr2[0]);
base_sort_ISD(arr2, size2);
for (int i = 0; i < size2; i++)
printf("%d ", arr2[i]);
printf("\n");
int arr3[] = {49, 38, 65, 97, 76, 13, 27, 49, 132, 134};
int size3 = sizeof(arr3) / sizeof(arr3[0]);
buck_sort(arr3, size3);
for (int i = 0; i < size3; i++)
printf("%d ", arr3[i]);
printf("\n");
return 0;
}
/*
int main(void)
{
int arr[] = { 9, 2, 5, 8, 3, 4, 7, 1, 6, 10};
HeapSort(arr, 10);
for (int i = 0; i < 10; i++) cout << arr[i] << ' '; cout << endl; return 0; }
*/