写在前面
代码上传GitHub交换排序(冒泡&&快排)
冒泡排序
冒泡排序其实是非常简单,他就是把一个数与他的前一个数在比较与交换的过程;
这个简单,我就直接上代码了:
版本一:
//最简单直接,但是效率不高
void BulleSort(int* array, int size)
{
for(size_t i = 0; i < size; i++)
{
for(size_t j = 0; j < size - i - 1; j++)
{
if(array[j] > array[j + 1])
swap(array[j], array[j + 1]);
}
}
}
版本二:
void BulleSort(int* array, int size)
{
int j, k;
bool flag;
flag = true;
k = size;
while(flag)
{
flag = false;
for(size_t j = 1; j < size; j++)
{
if(array[j] < array[j - 1])
{
swap(array[j], array[j - 1]);
flag = true;
}
}
k--;
}
}
快速排序
快排的答题思路就是这个样子,但是我们需要进一步进行深挖:
快排第一种:
左右指针法:
1. 选好一个基准值以后,左指针从左向右找第一个大于基准值的数,找到后停下;
2. 右指针从右向左找第一个小于基准值的数,找到后停下;
3. 然后进行左右交换;
4. 递归式的寻找,直到有序
int PortSort(int* array, int left, int right)
{
int mid = GetMidIndex(array, left, right);
swap(array[mid], array[right]);
assert(array);
int key = right;
while(left < right)
{
while(array[left] < array[key])
left++;
while(array[right] > array[key])
right--;
if(array[left] != array[right])
swap(array[left], array[right]);
}
swap(array[left], array[key]);
return left;
}
快排2
挖坑法
1. 其实和左右指针差不多,就是把数据拿出来了,新数据直接放里面就可以了;
2. 从左向右遍历,找到大于基准值的就放到基准值的位置;
3. 从右向左遍历,找到小于基准值的就放到上一个空位置;
4. 循环递归就可以;
int PortSort(int* array, int left, int right)
{
int mid = GetMidIndex(array, left, right);
swap(array[mid], array[right]);
assert(array);
int hole = array[right];
while(left < right)
{
while(array[left] < hole)
left++;
if(left < right)
array[right--] = array[left];
while(array[right] > hole)
right++;
if(left < right)
array[left++] = array[right];
}
array[left] = hole;
return left;
}
快排3
前后指针法:
1. 用两个指针标识2个数;
2. 当第二个指针小于基准值并且++第一个指针后不等于第二个指针,就说明第一个指针已经是大于基准值的了;其实可能折磨描述不太好理解,下面配上代码,就一目了然了;
3. 然后在自增第二个指针;
4. 依次循环递归即可;
int PortSort3(int *array, int left, int right)
{
int mid = GetMidIndex(array, left, right);
swap(array[mid], array[right]);
int pCur = left;
int pPre = pCur - 1;
int key = array[right];
while(pCur != right)
{
if(array[pCur] < key && array[++pPre] != array[pCur])
swap(array[pPre], array[pCur]);
++pCur;
}
swap(array[++pPre], array[pCur]);
}
快排的优化
- 我们都知道在快排中,我们要选取基准值,如果基准值选的是最中间的值,那么我们的排序效率将会比较高,但是如果选个最小的值,那么它快排的效率将完全体现不出来了,所以针对基准值的取法,进行优化是一件很重要的事;
//优化1: 三数取中法,不管什么情况下,返回去的都是大小适中的值
int GetMidIndex(int* array, int left, int right)
{
int mid = left + ((right - left) >> 1);
if (array[left] < array[mid])
{
if (array[mid] < array[right])
return mid;
else if (array[left] < array[right])
return right;
else
return left;
}
else
{
if (array[mid] > array[right])
return mid;
else if (array[left] > array[right])
return right;
else
return left;
}
}
- 当划分的子序列很小的时候(一般认为小于13个元素左右时),我们再使用快速排序对这些小序列排序反而不如直接插入排序高效。因为快速排序对数组进行划分最后就像一颗二叉树一样,当序列小于13个元素时我们再使用快排的话就相当于增加了二叉树的最后几层的结点数目,增加了递归的次数。所以我们在当子序列小于13个元素的时候就改用直接插入排序来对这些子序列进行排序。
void InsertSort(int *array, int n)
{
int end = 0;
for (size_t i = 1; i < n; i++)
{
int tmp = array[i];
end = i - 1;
while (end >= 0)
{
if (array[end] > tmp)
{
array[end + 1] = array[end];
--end;
}
}
array[end + 1] = tmp;
}
}
数据量太大时可能造成递归的深度太大,效率就太低,所以可以利用栈来实现
““
void QuickSortNodeR(int* array, int left, int right)
{
stack s;
s.push(right);
s.push(left);while (!s.empty())
{
int start = s.top();
s.pop();
int end = s.top();
s.pop();if (end > start) { int div = PortSort1(array, start, end); s.push(div - 1); s.push(start); s.push(right); s.push(div + 1); }
}
}
“`