偶然有空想到,对各种不同的排序算法进行一下总结。比较常用的排序算法有十种。
1.冒泡排序
思路:比较相邻的元素。如果第一个比第二个大,就交换它们两个;对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;针对所有的元素重复以上的步骤,除了最后一个;重复以上的步骤,直到排序完成。
代码:
void bubbleSort(int arr[])
{
int len = arr.length();
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j+1])
{
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
}
2.选择排序
思路:初始状态:无序区为R[1…n],有序区为空;第i次排序开始时,当前有序区和无序区分别为R[1…i-1]和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;n-1次排序结束之后,数组就有序化了。
代码:
void selectionSort( int arr[])
{
int len = arr.length();
int min;
for (int i = 0; i < len - 1; i++)
{
min = i;
for (int j = i + 1; j < len; j++)
{
if (arr[j] < arr[min])
{
min = j;
}
}
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
3.插入排序
思路:从第一个元素开始,将此元素认为已经被排序;取下一个元素,在已经排序的元素序列中从后向前扫描;如果该元素(已排序)大于新元素,将该元素移到下一位置;重复上一步骤,直到找到已排序的元素小于或者等于新元素的位置;将新元素插入到该位置后;重复之前的步骤。
代码:
void insertionSort(int arr[])
{
int len = arr.length();
int pre, cur;
for (int i = 1; i < len; i++)
{
pre = i - 1;
cur = arr[i];
while (pre >= 0 && arr[pre] > cur)
{
arr[pre + 1] = arr[pre];
pre--;
}
arr[pre + 1] = cur;
}
}
4.希尔排序
思路:是插入排序的改进;将待排序数组按照步长进行分组,然后将每组的元素利用直接插入排序的方法进行排序;通常最初采用数组的一半作为步长;每次将步长折半减小,循环上述操作;当步长为1时,利用直接插入,完成排序。
代码:
void shellSort(int arr[])
{
int i, j, gap, len = arr.length();
gap = len/2;
while (gap >= 1)
{
for (i = gap + 1; i <= len; i++)
{
arr[0] = arr[i];
j = i - gap;
while((j > 0)&&(arr[0] < arr[j]))
{
arr[j + d]= arr[j];
j = j - gap;
}
arr[j + d] = arr[0];
}
gap = gap/2;
}
5.归并排序
思路:采用分治法的思想,分为三步;分解:将n个元素分成个含n/2个元素的子序列;解决:用合并排序法对两个子序列递归的排序;合并:合并两个已排序的子序列已得到排序结果。
代码:
void mergesort(int arr[], int reg[], int start, int end)
{
if (start >= end)
return;
int len = end - start, mid = (len >> 1) + start;
int start1 = start, end1 = mid;
int start2 = mid + 1, end2 = end;
mergesort(arr, reg, start1, end1);
mergesort(arr, reg, start2, end2);
int k = start;
while (start1 <= end1 && start2 <= end2)
reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
while (start1 <= end1)
reg[k++] = arr[start1++];
while (start2 <= end2)
reg[k++] = arr[start2++];
for (k = start; k <= end; k++)
arr[k] = reg[k];
}
6.快速排序
思路:快速排序使用分治法来把一个串分为两个子串;从数列中挑出一个元素,称为 “基准”;重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置;递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
代码:
void quickSort(int arr[], int left, int right) {
if (left > right) {
return;
}
int i = left;
int j = right;
int base = arr[left];
while(i != j) {
while(arr[j] >= base && i<j) {
j--;
}
while(arr[i] <= base && i<j) {
i++;
}
if(i<j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
arr[left] = arr[i];
arr[i] = base;
quickSort(arr, left, i-1);
quickSort(arr, i+1, right);
}
7.堆排序
思路:使用堆这一数据结构进行排序;将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
代码:
void heapSort(int arr[], int n)
{
Build_Heap(arr, n);
for (int i = n - 1; i >= 0; i--)
{
swap(arr[0], arr[i]);
Heapify(arr, i, 0);
}
}
void Heapify(int tree[], int n, int m)
{
if (m >= n) return;
int c1 = 2 * m + 1;
int c2 = 2 * m + 2;
int max = m;
if (c1<n && tree[c1] > tree[max])
max = c1;
if (c2<n && tree[c2] > tree[max])
max = c2;
if (max != m) {
swap(tree[max], tree[m]);
Heapify(tree, n, max);
}
}
void Build_Heap(int arr[], int n)
{
int last_node = n - 1;
int last_heapify_node = (n-1)/2;
for (int i = last_heapify_node; i >= 0; i--)
{
Heapify(arr, n, i);
}
}
8.计数排序
思路:建立一个新数组C;找出待排序的数组中最大和最小的元素;统计数组中每个值为i的元素出现的次数,存入数组C的第i项;对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。
代码:
void countingSort(int arr[], int max)
{
int c[max + 1];
sorted = 0;
len = arr.length();
cen = max + 1;
for (int i = 0; i < len; i++)
{
if (!c[arr[i]])
{
c[arr[i]] = 0;
}
c[arr[i]]++;
}
for (int j = 0; j < cen; j++)
{
while(c[j] > 0)
{
arr[sorted++] = j;
c[j]--;
}
}
}
9.桶排序
思路:桶排序是计数排序的改进;定义一个映射函数来决定数据放入的桶及桶的数量;设置一个定量的数组当作空桶;遍历输入数据,并且把数据一个一个放到对应的桶里去;对每个不是空的桶进行排序;从不是空的桶里把排好序的数据拼接起来。
代码:
void bucketSort(int arr[] , int max)
{
int len = arr.length();
int tmparr[max + 1];
for(int i = 0; i <= max; i++)
tmparr[i] = 0;
for(int i = 0; i < len; i++)
tmparr[ arr[i] ]++;
for(int i = 0; i < max; i ++)
{
int j=0;
while( tmparr[i] != 0)
{
arr[j] = i;
j++;
tmparr[i]--;
}
}
}
10.基数排序
思路:取得数组中的最大数,并取得位数;arr为原始数组,从最低位开始取每个位组成radix数组;对radix进行计数排序(利用计数排序适用于小范围数的特点);
代码:
void radixSort(int arr[], int len)
{
int d=1;
int p=10;
for(int i=0;i<len;i++)
{
while(arr[i]>=p)
{
p=p*10;
d++;
}
}
int temp[len];
int count[10];
int radix=1;
for(int i=1;i<=d;i++)
{
for(int j=0;j<10;j++)
count[j]=0;
for(int j=0;j<n;j++)
{
int k=(arr[j]/radix)%10;
count[k]++;
}
for(int j=1;j<10;j++)
count[j]=count[j-1]+count[j];
for(int j=n-1;j>=0;j--)
{
k=(arr[j]/radix)%10;
temp[count[k]-1]=arr[j];
count[k]--;
}
for(int j=0;j<n;j++)
arr[j]=temp[j];
radix=radix*10;
}
}