相邻两两比较
,较大的下沉,较小的上升,第一轮之后最小的数就被放到了第一个位置,以此类推。
若某一次完了之后已经排好序,则没必要进行到len-1次,可用一个flag,没有交换之后就没必要再进行下去了 。
#include
#include
void bubbleSort(int a[],int length)
{
int len = length;
int temp;//中间变量
bool flag;//优化标志,判断是否有交换
for(int i=0;ii; j--)
{
if(a[j]
一开始就从原始序列中找到最小
的元素,放到序列的起始位置作为已排序序列,然后在剩下的未排序的元素中继续寻找最小的元素,放到已排序的序列末尾
,以此类推,直到所有的元素排列完毕。
void selectionSort(int a[],int length)
{
int len = length;
int minIndex;
int temp;
for(int i=0;i
在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。 插入排序在实现上,常采用in-place排序,因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位
,为最新元素提供插入空间。
小规模数据或者基本有序时十分高效,即数据有序程度越高,越高效
void insertSort(int a[],int length)
{
int len = length;
int temp;
int i;//已排好序的下一个元素(待排元素)的下标
int j;//有序序列的末尾
for(i=1;i=0&&a[j]>temp)
{//遍历有序序列,与要插入的元素比较
a[j+1] = a[j];//将元素后移,满足条件后移一个位置
j--;
}
a[j+1] = temp;//插入
}
}
将无序数组分割
为若干个子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列
,对各个子序列进行插入排序;然后再选择一个更小的增量,再将数组分割为多个子序列进行排序…最后选择增量为1,即使用直接插入排序,使最终数组成为有序。
逻辑上分组
),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高void insertI(int a[],int gap,int i)
{
int inserted = a[i];
int j=i-gap;
//插入的时候按组进行插入(组内元素两两相隔gap)
while(j>=0&& a[j]>inserted)
{
a[j+gap] = a[j];
j-=gap;
}
a[j+gap] = inserted;
}
void shellSort(int a[],int length)
{
int len= length;
//进行分组,最开始的增量 (gap)为数组长度的一半
for(int gap = len/2;gap>0;gap/=2)
{
//对各个分组进行插入排序
for(int i = gap; i
归并排序的实现分为递归实现
和非递归(迭代)实现
。
分治策略
的典型应用,我们将一个大问题分割成小问题分别解决,然后用所有小问题的答案来解决整个大问题。//递归
void mergeSort1(int a[],int left,int right,int *temp)
{//"分"的实现
int mid = 0;
if(left
堆
是一种近似完全二叉树的结构
(通常堆是通过一维数组来实现的),并满足性质:以最大堆(也叫大根堆、大顶堆)为例,其中父结点的值总是大于它的孩子节点。
void Swap(int A[], int i, int j)
{
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
void Heapify(int A[], int i, int size) // 从A[i]向下进行堆调整
{
int left_child = 2 * i + 1; // 左孩子索引
int right_child = 2 * i + 2; // 右孩子索引
int max = i; // 选出当前结点与其左右孩子三者之中的最大值
if (left_child < size && A[left_child] > A[max])
max = left_child;
if (right_child < size && A[right_child] > A[max])
max = right_child;
if (max != i)
{
Swap(A, i, max); // 把当前结点和它的最大(直接)子节点进行交换
Heapify(A, max, size); // 递归调用,继续从当前结点向下进行堆调整
}
}
int BuildHeap(int A[], int n) // 建堆,时间复杂度O(n)
{
int heap_size = n;
for (int i = heap_size / 2 - 1; i >= 0; i--) // 从每一个非叶结点开始向下进行堆调整
Heapify(A, i, heap_size);
return heap_size;
}
void heapSort(int a[],int len){
int heap_size = BuildHeap(a, len); // 建立一个最大堆
while (heap_size > 1) // 堆(无序区)元素个数大于1,未完成排序
{
// 将堆顶元素与堆的最后一个元素互换,并从堆中去掉最后一个元素
// 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
Swap(a, 0, --heap_size);
Heapify(a, 0, heap_size); // 从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn)
}
}
使用分治策略
来把一个序列分为两个子序列。
//方法一
void Swap(int A[], int i, int j)
{
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
int Partition(int A[], int left, int right) // 划分函数
{
int pivot = A[right]; // 这里每次都选择最后一个元素作为基准
int tail = left - 1; // tail为小于基准的子数组最后一个元素的索引
for (int i = left; i < right; i++) // 遍历基准以外的其他元素
{
if (A[i] <= pivot) // 把小于等于基准的元素放到前一个子数组末尾
{
Swap(A, ++tail, i);
}
}
Swap(A, tail + 1, right); // 最后把基准放到前一个子数组的后边,剩下的子数组既是大于基准的子数组
// 该操作很有可能把后面元素的稳定性打乱,所以快速排序是不稳定的排序算法
return tail + 1; // 返回基准的索引
}
void quickSort1(int a[],int left,int right){
if (left >= right)
return;
int pivot_index = Partition(a, left, right); // 基准的索引
quickSort(a, left, pivot_index - 1);
quickSort(a, pivot_index + 1, right);
}
//方法二
void quickSort2(int a[],int n){
int i,j;
int pivot = a[0]; //设置第一个数为基准值
i = 0;
j = n - 1;
while(i < j){
//大于基准值者保持在原位置
while(ipivot){j--;}
if(i1)
{
quicksort(a,i); //左序列进行快排
}
if(n-i-1>1)
{
quicksort(a+i+1,n-i-1);//右序列进行快排
}
}
参考原文:
1、https://blog.csdn.net/a951030393/article/details/80209490
2、https://blog.csdn.net/qq_39207948/article/details/80006224
3、https://blog.csdn.net/Moralin_/article/details/80491901