交换函数swap
//C++实现
void swap(int &left, int &right)
{
int temp = left;
left = right;
right=temp;
}
/*指针作为参数的交换函数
void swap1(int *left, int *right)
{
int temp = *left;
*left = *right;
*right = temp;
}
*/
【冒泡排序】
//C++实现
void bubble_sort(vector<int> &nums)
{
int size=nums.size();
for(int i=0;i<size;i++)
{
for(int j=1;j<size-i;j++)
{
if(nums[i]>nums[j])
swap(nums[i],nums[j]);
}
}
}
【冒泡排序改进】:使用flag做标记,当已经排序好之后就不需要遍历了
//C++实现
void bubble_sort_better(vector<int> &nums)
{
int size=nums.size();
for(int i=0;i<size && flag;i++)
{
int flag=0;
for(int j=1;j<size-i;j++)
{
if(nums[i]>nums[j])
{
flag=1;
swap(nums[i],nums[j]);
}
}
if(!flag) //如果flag一直保持0,表示并没有进行变换,表示后面的遍历都是增序,就需要再进行排序了
break;
}
}
【选择排序】
主要思想是:从0-size-1个元素中,逐个选做临时最小值【其实不一定是最小值】,然后再向后遍历,逐个比较,如果有元素比临时最小值要小的则保存其索引作为最小值的索引,直至遍历到数组末尾,此时将确认的最小值索引对应的值与临时最小值进行交换,依次类推,直至最后一个元素作为临时最小值,就完成排序过程
//C++实现
void choice_sort(vector<int> &nums)
{
int min_index; //记录当前循环最小值的索引
int size=nums.size();
for(int i=0;i<size;i++)
{
min_index=i;
for(int j=i+1;j<size;j++)
{
if(nums[j]<nums[i])
min_index=j;
}
swap(nums[i],nums[min_index]);
}
}
【插入排序】
逐个遍历数组元素并与他前一个元素比较,直至发现当前元素的值比前一个元素的值小,保存当前值到temp,然后逐个比较他的前一个值,比temp
大的元素,则往后移动一个位置,直至找到小于temp的元素,则将temp插入其后,再继续往后遍历,知道最后一个元素
//C++实现
void insert_sort(vector<int> &nums)
{
int size=nums.size();
for(int i=1;i<size;i++)
{
if(nums[i]<nums[i-1]) //出现后面小于前面的情况,插入排序
{
int temp=nums[i];
for(int j=i;nums[j-1]>temp && j>0;j--) //将大于temp的都往后挪一位
nums[j]=nums[j-1];
nums[j]=temp; //将temp插入到最后一个比他大的元素前面
}
}
}
【希尔排序】:通过从小到大逐渐减小increment的值,逐步将数组排成大致递增的,
/C++实现
void shell_sort(vector<int> &nums)
{
int size=nums.size();
int increment; //增量;可以理解成交换的步长
for (increment = size / 2;increment > 0;increment /= 2) //以2的倍数递减增量,当然增量还可以是其他方法确定,只要确保
//最后一次遍历的增量为1即可
{
for (i = increment;i < size;i++)
{
if(nums[i] < nums[increment])
swap(nums[i],nums[increment]);
}
}
}
【归并排序】
采用分治的思想,先将整个数组按二分的方法逐步分解,最后分解成单个元素,然后再利用merge函数,将两个子数组合并到一个增序数组;依此类推,直至将整个数组排序成一个增序数组
//C++实现
//两个子数组合并函数:$1:子数组所在的数组 $2:第一个子数组的起点 $3:第一个子数组的终点 $4:第二个子数组的终点
void merge(vector<int> &nums , int first , int mid , int tail)
{
vector<int> temp;
int left=first;
int right=mid+1;
while(left <= mid && right <= tail)
{
if(nums[left] <= nums[right])
temp.push_back(nums[left++]);
else
temp.push_back(nums[right++]);
}
while(left<=mid)
temp.push_back(nums[left]);
while(right<=tail)
temp.push_back(nums[right]);
int j=0;
for(int i=first;i<=tail && j<temp.size();i++)
nums[i]=temp[j++];
}
/*递归实现*/
void merge_sort(vector<int> &nums , int first , int tail)
{
if(first == tail) //递归停止条件
return ;
int mid=0;
while(first<tail)
{
mid=(first+tail)/2;
merge_sort(first,mid);
merge_sort(mid+1,tail);
merge(nums,first,mid,tail);
}
}
/*非递归实现*/
//将待排序的数组按照顺序两两配对排序,然后在递增步长,以每四个元素进行配对排序,这样迭代下去就能将所有的子数组排序完
void merge_sort_diedai(vector<int> &nums)
{
int size=nums.size();
int first; //记录子数组的第一个元素索引
int tail; //记录子数组的中间元素索引
int mid; //记录子数组的最后一个元素索引
for (int i = 1; i < size; i *= 2) //每次进行子数组合并的步长:1、2、4、8。。。
{
first = 0;
while (first + i < size) //最后一个子数组存在(需要归并)
{
mid = first + i - 1;
tail = mid + i < size ? mid + i : size - 1;//最后一个子数组可能不够大,此时就需要跟size来确定tail的值
Merge(nums, first, mid, tail);
first = tail + 1;
}
}
}
【堆排序】:堆是一个完全二叉树。大顶堆:其每个节点的值都大于左右子节点的值 小顶堆:每个节点的值都小于等于其左右子节点的值
以下是我对于堆排序的一些理解,作图比较直观,容易理解
//C++实现
void Heapify(vector<int> &nums, int i, int size) // 从A[i]向下进行堆调整
{
//当前节点为非叶结点,则在完全二叉树里面,他的左右子节点的索引分别为2*i+1和2*i+2;
int left_child = 2 * i + 1; //左孩子索引
int right_child = 2 * i + 2; //右孩子索引
int max_index = i; //选出当前结点与其左右孩子三者之中的最大值的索引,初始化为当前节点的索引
if (left_child < size && nums[left_child] > nums[max_index])
max_index = left_child;
if (right_child < size && nums[right_child] > nums[max_index])
max_index = right_child;
if (max_index != i) //当三个节点中,最大值不是当前节点,要将当前节点的值与最大值所在的节点进行交换
swap(nums,i,max_index); // 把当前结点和它的最大(直接)子节点进行交换
}
void heap_sort(vector<int> &nums)
{
int heap_size=nums.size();
// 建立一个大顶堆
//在一个完全二叉树中,他的非叶结点为其前面(size/2-1)个节点,往后的都是叶结点
for (int i = heap_size / 2 - 1; i >= 0; i--) //从每一个非叶结点开始向下进行堆调整
Heapify(nums, i, heap_size);
while (heap_size > 1) // 堆(无序区)元素个数大于1,未完成排序
{
// 将堆顶元素与堆的最后一个元素互换,并从堆中去掉最后一个元素
// 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
Swap(nums,0,--heap_size); //将最后一个元素和第一个元素互换,并且heap_size--,去掉最后一个元素再接着循环
for (int i = heap_size / 2 - 1; i >= 0; i--)
Heapify(nums, i, heap_size); //互换后重新构建大顶堆,时间复杂度O(logn)
}
}
【快速排序】
//C++实现
//分区处理,将待排序数组按照基准值分成左右子数组,保证左子数组全部小于右子数组,并且找出基准值对应的分界索引值
int partition(vector<int> &nums,int first,int tail)
{
int left=first;
int right=tail;
int temp = nums[left]; //留作基准值
while(left < right) //直到left=right,此时基准值左边全部小于右边
{
while(left < right && nums[right] >= temp) //从右往左遍历,直到遇到小于基准值的元素为止,保证right右边全是大于基准值的
right--;
swap(nums,left,right); //交换一次,基准值被交换到nums[right]
while(left < right && nums[left] <= temp) //从left开始遍历,直到找到大于基准值的元素,保证left左边全部小于基准值
left++;
swap(nums,left,right); //再交换一次,此时基准值被交换回nums[left]
}
return left;
}
//递归函数
void quick_sort(vector<int> &nums,int low,int high)
{
int pivot;
if(low < high)
{
pivot = partition(nums,low,high); //将待排序数组分成基准值左右两个子数组
quick_sort(nums,low,pivot-1); //递归进行,将基准值左子数组进行分区处理
quick_sort(pivot+1,high); //递归进行,将基准值右子数组进行分区处理
}
else //递归终止条件
return ;
}
main()
{
quick_sort(nums,0,nums.size()-1);
}
这两篇博客我觉得都写得挺不错的,其中也有参考他们的算法,有兴趣的可以仔细地看一下