冒泡排序
快速排序
插入排序
选择排序
希尔排序
堆排序
归并排序
1.冒泡排序
冒泡排序采用两两比较的方式。如果要由小到大排序,并且从前往后遍历,那么将大的往后放,第一重循环是比较几轮,也就是数组个数,第二重循环是从 0 到总数减去轮数。
// 冒泡排序
void myBubble(vector<int> &values)
{
int temp = 0;
for (int i = 0; i < values.size(); i++)
{
for (int j = 0; j < values.size() - i - 1; j++)
{
// 由小到大
if (values[j] > values[j+1])
{
temp = values[j + 1];
values[j + 1] = values[j];
values[j] = temp;
/* 不用额外的空间方法
values[j + 1] ^= values[j];
values[j] ^= values[j+1];
values[j+1] ^= values[j];
*/
}
}
}
}
2.快速排序
快速排序就是选择一个基准数据,然后在数组中 后前 依次判断,如果是由小到大的,那么大的应该在基准右侧,小的在基准左侧,所以找到不满足的就交换位置。
注意:快速排序在递归时,必须判断左侧标志否小于右侧,否则递归无法退出
如果基准选择的是最左侧的数据,那么就应该先从右侧判断,因为左侧基准已经记录的值,所以右侧找到需要交换的数据可以赋值,否则会覆盖掉数组的值
在比较的时候必须用 <= 和 >= ,否则碰到两个相同的数据就会陷入死循环。
// 快速排序
int partition(vector<int> &values, int low, int high)
{
if (low >= 0)
{
int temp = values[low];
while (low < high)
{
// 由小到大
while (low < high && values[high] >= temp)
{
high--;
}
values[low] = values[high];
while (low < high && values[low] <= temp)
{
low++;
}
values[high] = values[low];
}
values[low] = temp;
}
return low;
}
void quickSort(vector<int> &values,int low, int high)
{
if (low < high)
{
int middle = partition(values, low, high);
quickSort(values,low,middle - 1);
quickSort(values, middle + 1, high);
}
}
3.插入排序
遍历元素,与前边的元素比较,从小到大的话,如果需要前置,那么将上一个元素后移,直到找到合适位置,第二重循环的 j 可以看作指向 坑 在哪,将前边的元素放进坑中。
// 插入排序
void insertSort(vector<int> &values)
{
for (size_t i = 1; i < values.size(); i++)
{
int temp = values[i];
// 由小到大
size_t j = i;
for (; j >= 1 && temp < values[j - 1]; j--)
{
values[j] = values[j - 1];
}
values[j] = temp;
}
}
4.希尔排序
与直接插入排序相似,只不过比较不是逐个比较,而是有一个增量,每次移动一个增量。
// 希尔排序
void shellSort(vector<int> &values)
{
if (values.size() > 0)
{
int gap = values.size();
while (1 != gap)
{
gap /= 2;
for (size_t i = gap; i < values.size(); i++)
{
int temp = values[i];
int j = i;
for (; j >= gap && temp < values[j - gap]; j -= gap)
{
values[j] = values[j - gap];
}
values[j] = temp;
}
}
}
}
5.选择排序(擂台法)
依次遍历数组,由小到大是找到最小值并且记录下标,然后交换数值
// 选择排序
void selectSort(vector<int> &values)
{
if (values.size() > 0)
{
for (size_t i = 0; i < values.size(); i++)
{
int min = values[i];
size_t n = i;
size_t j = i + 1;
for (; j < values.size(); j++)
{
if (min > values[j])
{
min = values[j];
n = j;
}
}
values[n] = values[i];
values[i] = min;
}
}
}
6.堆排序
堆排序首先是建立一个大顶堆,即所有的父节点都大于子节点的二叉树,然后取出最大值:与最后一个交换,将前边的继续建立大顶堆,然后继续取最大的放到最后,直至结束。
建立大顶堆的算法:因为初始数组,只有前一部分有子节点,所以,从中间往前来建立,如果当前节点小于两个子节点中最大的子节点,那么就交换位置,然后继续判断在交换后的位置是否子节点仍然大于父节点,大于的话继续交换,直至不再大于,就到下一个父节点,从而建立成功。
// 堆排序
int leftChild(int i)
{
return 2 * i + 1;
}
void swap(vector<int> &values, int i, int j)
{
int temp = values[i];
values[i] = values[j];
values[j] = temp;
}
void createMaxHeap(vector<int> &values, int i, int length)
{
int child = 0;
int temp = values[i];
for (; leftChild(i) < length; i = child)
{
child = leftChild(i);
if (child != length - 1 && values[child] < values[child + 1])
{
child++; // 选择大的子节点
}
if (temp < values[child])
{
values[i] = values[child]; // 如果子节点大,就与父节点交换
}
else
{
break;
}
}
values[i] = temp; //
}
void heapSort(vector<int> &values)
{
for (int i = values.size() / 2; i >= 0; i--)
{
createMaxHeap(values,i,values.size());
}
for (size_t i = values.size() - 1; i > 0 ; i--)
{
swap(values,0,i);
createMaxHeap(values,0,i);
}
}
7.归并排序
首先是 归 即递归,递归来分治数组,不断的划分数组。
然后是 并 即合并,合并来排序。
所以可以先设计合并有序数组的算法,创建中间数组来存储合并后的数据。
然后递归调用即可。
// 归并排序
void mergeArray(vector<int> &values, int left, int mid, int right, vector<int> & temp_vec)
{
int k = 0;
int i = left;
int j = mid + 1;
// 合并有序数组
while (i <= mid && j <= right)
{
if (values[i] <= values[j])
{
temp_vec[k++] = values[i++];
}
else
{
temp_vec[k++] = values[j++];
}
}
// 左边的没有排完
while(i <= mid)
{
temp_vec[k++] = values[i++];
}
// 右边的没有排完
while (j <= right)
{
temp_vec[k++] = values[j++];
}
// 赋值
for (size_t m = 0; m < k; m++)
{
values[m + left] = temp_vec[m];
}
}
void mergeSort(vector<int> &values, int left, int right)
{
if (left < right)
{
int mid = (left + right) / 2;
mergeSort(values, left, mid);
mergeSort(values,mid + 1,right);
vector<int> temp_vec = values;
mergeArray(values,left,mid,right,temp_vec);
}
}