C++各种常见排序算法

来源:互联网 发布:银河麒麟linux下载 编辑:程序博客网 时间:2024/06/08 12:22

1.冒泡排序

<1>冒泡排序的本质在于每一趟循环从数组的头走到尾找到最大的值放在最右边,下一次循环继续从剩下的n-1个数中寻找最大值放到最右边。直到剩下最后俩个数比较交换后结束。

<2>比较方式也简单易懂,拿升序为例,用a[i]与a[i+1]比较,如果a[i]>a[i+1],swap(a[i],a[i+1]),当然,如果10个数进行排序,比较九次就可以确定这十个数中的最大值。简单的代码实现如下:
void BubbleSort(int* a,int size)
{
assert(a);
for (int i = 0; i < size - 1; i++)
{
for (int j = 0; j < size - 1 - i; j++)
{
if (a[j]>a[j + 1])
swap(a[j], a[j + 1]);
}
}

2.插入排序

<1>插入排序的思想自然就是以插入为主,当然最主要的排序思路必然是先单趟再进行循环,第一步先掌握单趟排序的过程。插入排序每一趟将当前位置的数调整到新的有序序列当中。
<2>如果俩个数进行排序,以升序为例 2 , 1 用第一个数与第二个数进行比较,实现保存好第二个位置的值 temp=a[end+1],将大的值赋给a[second],如果事先没有存好第二个位置的值的话此时就找不到原本第二个位置的值了。接下来要做的自然就是a[end]=temp, 这样就完成了俩个数的排序。
<3>但是多个数进行排序的时候如:3,4,5,1,2 进行排序的时候,当进行到第三个数的时候,此时i=end=2,当 2 与 1 交换以后,–end,end<0时循环结束,整个过程就是,1与5比较以后1到了5的位置,1再与4进行比较交换,再与3 进行比较交换,此时end<0,循环结束,完成这一趟排序。
<4>由上可知,我们需要进行n-1躺上述排序,整体代码如下:
void InsertSort(int*a, int size)//插入排序
{
assert(a);
for (int i = 0; i < size - 1; i++)
{
int end = i;
int temp = a[end + 1];
while (end >= 0)
{
if (a[end]>temp)
{
a[end + 1] = a[end];
end–;
}
else
{
break;
}
}
a[end + 1] = temp;

}

}

3.希尔排序

<1>希尔排序像是插入排序的升级版本,主要用来出来数量庞大元素之间的排序。将需要排序的对象先排序为gap个数为一组的有序的序列,初始值为n,逐渐减小gap值,当gap为1时,自然就和插入排序一样了。
<2>通常我们将gap=gap/3+1,所以当gap为1时达到排序目的。
<3>需要理解的是外层循环条件的控制,插入排序相当于gap为1,自然就是n-1次,也就是n-gap次。因为要分割为每个组为gap个数的多个有序序列,所以a[end]应与a[end+gap]进行比较。代码如下:
void ShellSort(int*a, int size)//希尔排序
{
assert(a);
int gap = size;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0; i < size - gap; i++)
{
int end = i;
int temp = a[end + gap];
while (end >= 0)
{
if (a[end]>temp)
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
a[end + gap] = temp;
}
}
}
}

4.选择排序

<1>选择排序的重点自然是在于如何选择,其单趟排序完成当前序列最大值与最小值的放置。
<2>我们定义俩个变量min,max用来存放实时的最小值与最大值,等到一便走完以后分别将其放到a[left]与a[right],left++,right–,直到left,与right相遇后比较结束,完成排序,代码如下:
void SelectSort(int*a, int size)//选择排序
{
assert(a);
int left = 0;
int right = size - 1;

while (left < right){    size_t min = left;    size_t max = right;    for (int i = left; i <= right; i++)    {        if (a[i] < a[min])        {            min = i;        }        if (a[i]>a[max])        {            max = i;        }    }    swap(a[left], a[min]);    if (max == left)/*如果left位置确定为最大值,上面的交换将其换到了最小值的位置,特做以下处理。*/    {        max = min;    }    swap(a[max], a[right]);    left++;    right--;}

}

5.堆排序

<1>利用堆进行排序,自然首先要建堆。升序键大堆,降序建小堆。建堆的过程需要调整算法,调整次数取决与最后一个非叶结点的位置。pos=(n-2)/2,也是从这个位置开始调整,直至根节点完成建堆。
<2>堆顶数据自然是堆中最大的数,将它与最后一个位置的值进行交换,再进行一次调整,对前n-1个数进行调整。持续这个过程直至n小于0.代码如下:
void AdJustDown(int*a, int size, int root)
{
int parent = root;
int child = 2 * parent + 1;
while (child < size)
{
if (child + 1 < size&&a[child + 1] > a[child])
child++;
if (a[child]>a[parent])
{
swap(a[child], a[parent]);

        parent = child;        child = parent * 2 + 1;    }    else        break;}

}
void HeapSort(int *a, int size)
{
for (int i = (size - 2) / 2; i >= 0; i–)
AdJustDown(a, size, i);
int end = size - 1;
while (end>=0)
{
swap(a[0], a[end]);
AdJustDown(a, end,0);
–end;
}
}

6.快速排序

<1>快速排序是我们最常用到的适用面也比较广泛的排序方法,其思想是每次以数组中的一个key值为分割点,使左边值小于它,右边值大于它。分为俩部分以后转变为子问题在进行分割,直到变为剩下一个值的有序空间。
<2>所以快速排序的关键在于如何进行分割,我们通常取数组最后一个位置的数据为key值,当然要是这个位置的值最大或最小的话就降低效率了,也可以取随机数,或者用三数取中法使快排时间复杂度控制在nlgn。
<3>获取key值并进行第一趟排序有三种方式分别为左右指针法、挖坑法以及俩个指针尾随法。
①左右指针:取key=a[right],左边从left开始,右边从right开始,分别与key值比较,左边遇到比key大的停下来,右边开始走,遇到比key小的停下来a[begin]与a[end]交换。走到循环结束a[begin]或a[end]与a[right]进行交换,完成第一趟排序。
②挖坑法:取key=a[right],同样a[begin]往后走遇到比key值大的停下来,a[end]=a[begin];a[end]往前走遇到比key值小的停下来,a[begin]=a[end],循环结束,a[begin]=key,完成第一趟排序。
③俩个指针尾随法:取key=a[right],cur=left,prev=left-1,cur遇到比key值小的,prev++,cur++,遇到比key值大的停下来如果++prev!=cur,swap(a[cur],a[++prev]),否则cur++,直至cur=right,swap(a[prev],a[right]),完成第一趟排序。
<4>接受单趟排序返回值,进行递归调用,代码如下:
int Sort2(int* a, int left, int right)//俩个指针法
{
int cur = left;
int prev = left -1;
int key = a[right];
while (cur < right)
{
if (a[cur] < key && ++prev != cur)
{
swap(a[prev], a[cur]);
}
++cur;

}    swap(a[right], a[++prev]);return prev;

}
int Sort1(int*a, int left,int right)//挖坑法
{
if (left < right)
{
int begin = left;
int end = right;
int key = a[end];
while (begin < end)
{
while (begin < end && a[begin] <= key)
{
begin++;
}
a[end] = a[begin];
while (begin < end && a[end] >= key)
{
end–;
}
a[begin] = a[end];
}
a[begin] = key;
return begin;
}
}

int Sort3(int*a, int left, int right)//左右指针法
{
assert(a);
int begin = left;
int end = right;
int key = a[right];
while (begin < end)
{
while (begin < end &&(a[begin]

7.归并排序

<1>归并排序主要思路是将n个含有m个数据的有序序列合在一起,不断的二分使得m变为1,达到排序的目的。
<2>所以拿到一组数据后,先分再合,这里我们先开辟和原有空间相同大小的空间将分开后的数据一一拷到新的空间完成排序,代码如下:
void Merge(int *a, int *temp,int begin1,int end1,int begin2,int end2)
{
assert(a&&temp);
size_t pos = begin1;
size_t index = begin1;
while (begin1 <= end1&&begin2 <= end2)
{
if (a[begin1] > a[begin2])
{
temp[index++] = a[begin2++];
}
else
{
temp[index++] = a[begin1++];
}
}
while (begin1 <= end1)
{
temp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
temp[index++] = a[begin2++];
}
memcpy(a + pos, temp + pos, sizeof(int)*(end2 - pos + 1));
}

void _MergeSort(int *a, int*temp, int left, int right)
{
assert(a&&temp);
int mid = left + (left - right) / 2;
_MergeSort(a, temp, left, mid );
_MergeSort(a, temp, mid + 1, right);
Merge(a, temp, left, mid , mid + 1, right);

}
void MergeSort(int*a, int size)
{
assert(a);
int*temp = new int[size];
_MergeSort(a, temp, 0, size - 1);
delete[] temp;
}

原创粉丝点击