目录
前言
听说面试会容易问起这个简单的算法,所以复习一下顺便写个文章记录一下。
推荐一个可视化网站,可以看一些算法的运行步骤。
一、算法比较
二、算法实现(默认升序)
1、冒泡排序
循环n-1次,每次从0开始与n比较,保证n为大值,直到循环到len-n时,此时的
//冒泡排序
void bubble_sort(int *nums,int len)
{
for (int i = 0; i < len; i++)
{
//遍历整个数组寻找最大值,因为已经遍历了i次,寻找出了i个大值,所有只需要再遍历len-1-i次
for (int j = 0; j < len-1-i; j++)
{
//判断两数大小,不符合排序规则就进行交换
if (nums[j] > nums[j + 1])
{
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
}
2、选择排序
遍历n-1次数组,每次寻找出最小值,存放在第n-1的位置上。
//选择排序
void select_sort(int *nums, int len)
{
for (int i = 0; i < len-1; i++)
{
//记录最小值的下标
int minIndex = i;
for (int j = i+1; j < len; j++)
{
//判断新元素是否是小值
if (nums[minIndex] > nums[j])
{
minIndex = j;
}
}
//如果最小值不是i就进行交换
if (i != minIndex)
{
int temp = nums[i];
nums[i] = nums[minIndex];
nums[minIndex] = temp;
}
}
}
3、插入排序
循环n-1次,将n前面的数看作为有序排列,将n+1元素插入到前n个排列中。
//插入排序
void insert_sort(int *nums, int len)
{
for (int i = 0; i < len-1; i++)
{
//将第i+1个元素插入前i个数中
int cur = nums[i + 1];
for (int j = i ; j >= 0; j--)
{
//查找插入的位置
if (nums[j] > cur)
{
//i+1的值更小,往移位给i+1腾位置
nums[j + 1] = nums[j];
}
else
{
//插入合适的位置
nums[j + 1] = cur;
break;
}
}
}
}
4、希尔排序
按照n/2的间距先进行元素的两两排序,然后将间距-1,直到间距为1。
//希尔排序
void shell_sort(int *nums, int len)
{
//间距从len/2开始
int temp, gap = len / 2;
//间距>=1
while (gap > 0)
{
for (int i = gap; i < len; i++)
{
//记录当前值
temp = nums[i];
//间距相同的上一个元素
int preIndex = i - gap;
while (nums[preIndex] > temp && preIndex >= 0)
{
//判断间距相同的前面的元素的大小
nums[preIndex+gap] = nums[preIndex];
preIndex -= gap;
}
nums[preIndex + gap] = temp;
}
gap /= 2;
}
}
5、并归排序
先将数组二分直到分成每个组只有1,然后再两两比较连接在一起。遍历了n/2次。
//并归排序
void merge(int *nums, int len)
{
int *temp = new int[len];
int index = 0;
int mid = len / 2;
int first = 0, second = mid;
//二个有序数组合成一个
while (first < mid && second < len)
{
//判断大小
if (nums[first] < nums[second]) temp[index++] = nums[first++];
else temp[index++] = nums[second++];
}
//将两边剩下的值进行写入
while (first < mid) temp[index++] = nums[first++];
while(second<len) temp[index++] = nums[second++];
//赋值给返回值
for (int i = 0; i < len; i++)
{
nums[i] = temp[i];
}
}
void merge_sort(int *nums, int len)
{
//当分成1之后就不能再分,返回递归
if (len <= 1) return;
if (len > 1)
{
//继续二分
merge_sort(nums,len/2);
merge_sort(nums+ len /2, len - len / 2);
//进行融合
merge(nums,len);
}
}
6、快速排序
利用了递归的思想,以初始值左值为基准将小于左值的数交换到左边,然后更换基准值位置进行递归排序。
//快速排序
void quick_sort(int nums[], int _left,int _right)
{
int left = _left;
int right = _right;
//设置递归完成条件
if (left >= right) return;
//设置基准值
int temp = nums[left];
while (left != right)
{
//查找右边小于基准值,并进行交换
while (temp <= nums[right] && right>left) right--;
nums[left] = nums[right];
//查找左边大于基准值,并进行交换
while (temp >= nums[left] && right > left) left++;
nums[right] = nums[left];
}
//改变基准值
nums[left] = temp;
quick_sort(nums, _left, left-1);
quick_sort(nums, right + 1, _right);
}
7、堆排序
利用了二叉树的构造思想,将最大的元素放在堆顶部,然后与末尾位置进行交换。遍历n-1次
//堆排序
void heap_adjust(int *nums, int start, int end)
{
int parent = start;
int child = start * 2 + 1;
while (child < end)
{
if (child + 1 < end && nums[child] < nums[child + 1])
{
//寻找两个节点的最大值
child++;
}
if (nums[parent] > nums[child])
{
//不进行交换
return;
}
else
{
//寻找到更大值,进行交换
int temp = nums[parent];
nums[parent] = nums[child];
nums[child] = temp;
//比较下一层节点
parent = child;
child = parent * 2 + 1;
}
}
}
void heap_sort(int *nums, int len)
{
for (int i = len / 2 - 1; i >= 0; i--)
{
heap_adjust(nums,i,len);
}
for (int i = len - 1; i > 0; i--)
{
int temp = nums[0];
nums[0] = nums[i];
nums[i] = temp; //交换顶点
heap_adjust(nums,0,i);
}
}
8、计数排序
找出数组元素的最大值,申请最大值大小的数组并且初始化为0,然后将原数组的每个值作为新数组的下标进行++,最后遍历新数组判断其值是否>0,即可知道原数组值的排序。
//计数排序
void count_sort(int *nums, int len)
{
int max_num = 0;
for (int i = 0; i < len; i++)
{
//获取数组的最大值
if (nums[i] > max_num)
{
max_num = nums[i];
}
}
max_num++;
int *temp = new int[max_num];
//memset(temp,0,sizeof temp); //不知道为什么不行
//初始化数组
for (int i = 0; i < max_num; i++)
{
temp[i] = 0;
}
for (int i = 0; i < len; i++)
{
//将出现的次数存入数组中
temp[nums[i]]++;
}
int index = 0;
for (int i = 1; i < max_num; i++)
{
//出现的次数不为0时,将下标存入返回的数组中
while (temp[i]--)
{
nums[index++] = i;
}
}
delete[] temp;
}
9、桶排序
桶排序的思想就是先计算出原数组的最大值和最小值的差值,然后分成若干个相同间距的区间,然后将原数组的值落在相应的区间中进行排序,最后组合起来。
暂未实现只用数组版本,后续写出来了再补上
10、基数排序
先找出最大的位数,然后依次从最小位取余开始比较排序,直到比较到最大位数。
//基数排序
int getMaxDigital(int *nums, int len)
{
int res = 1;
int temp = 10;
for (int i = 0; i < len; i++)
{
while (nums[i] >= temp)
{
temp *= 10;
res++;
}
}
/*cout << "max:" << res << endl;*/
return res;
}
void radix_sort(int *nums, int len)
{
int maxNum = getMaxDigital(nums, len);
int *temp = new int[len];
int start[10] = {0}; //记录每个数的前面的总个数+1也就是每个位置的起始值
int count[10] = {0}; //记录每个位置(1-9)的个数
int base = 10;
while (maxNum--)
{
for (int i = 0; i < len; i++)
{
//先遍历一遍,取出当前位数并且记录个数在count中
count[nums[i] / base % 10]++;
}
for (int i = 1; i < 10; i++)
{
//记录每个位数上1-9的起始下标
start[i] = count[i - 1] + start[i - 1];
}
for (int i = 0; i < len; i++)
{
//根据每个数的位数上的值排序
int index = nums[i] / base % 10;
temp[start[index]++] = nums[i];
}
//排序好的值赋值给nums进行下个位数的循环
for (int i = 0; i < len; i++)
{
nums[i] = temp[i];
}
base *= 10;
}
}
总结
本人是个菜鸟,上述的一些算法都没有进行理论的分析、时间/空间复杂度的分析以及稳定的分析,代码写的也不是很严谨,没有进行一些特殊情况的判断。如有错误请大佬勿喷。