概述
插入排序:
插入排序的思路就是,前面的数组已经有序(从第二个数看来,第一个数已经有序了,它只要找到自己的插入点插入就行了;然后第三个数看前两个数都已经有序了....以此类推),下标为i的这个值依次与前面的值比较,找到合适的地方就可以直接插入了。但是,数组的插入是需要插入位以后的数据全部后移,所以我们边比较边移位,这样才能在找到合适位置的情况下直接插入。
代码如下:
void insert_sort(int arr[],int len)
{
for (int i = 0; i < len-1; i++) //把下标为i的元素插入到前面有序的数组中
{
int num = arr[i+1]; //i=0时只有一个数肯定是有序的 因此从第二个数记录要插入的值
int j = 0;
for (j = i;j>=0;j--)
{
if (arr[j] > num) //如果前面的数大于记录的值
{
arr[j+1] = arr[j]; //那么数往后移动 这里不用担心覆盖 因为i+1的值已经被记录在num里了
}
else
{
break; // arr[j]小于num 说明找到了可以插入的位置arr[j+1]
}
}
arr[j+1] = num; //插入
}
}
插入排序分直接插入和折半插入,时间复杂度都为O(n^2)
上面的就是直接插入 ,对于直接插入我们发现效率不是很高,每次要找到插入点都需要遍历前面的部分数组,运气好第一个就是,运气不好要遍历全部。因此,折半插入做到了优化,每次都与有序数组(这里与上述一样)的中间值比较,如果值小于中间值,说明要插入的地方在中间值左侧,反之则在右侧。
代码如下:
void binary_insertsort(int arr[],int len)
{
for (int i = 0; i < len-1; i++)
{
int num= arr[i+1]; //插入数的下标从1开始
int left = 0; //左区间
int right = i; //右区间 [0,i]
while(left <= right)
{
int mid = (left+right)/2; //中间值下标
if (num < arr[mid])
{
right = mid-1; //小 说明插入位置在左侧 [0,mid-1]
}
else
{
left = mid+1; //大 说明在右侧 [mid+1,i]
}
}
for (int j = i; j >= left ; j--)
{
arr[j+1] = arr[j]; //数据后移
}
arr[left] = num; //插入
}
}
快速排序:
快速排序的思想光是用文字描述有点吃力,所以我画了张图来便于理解。
这里需要几个参数 一个是pos(position,基准位置) 一个是 key (基准值) ,快速排序中有个基准值的概念,在当前循环下,基准值左边的数要小于基准值,右边的数要大于基准值。下面我用图来解释下这是如何实现的
首先,第一个基准值为3,下标为0。记key = 3; pos = 0; left ,right为当前需要排序的区间
第一次循环时,我们先从右边往左看,发现,右边第一个数(1)就小于key值(3),按照基准值的概念,右边的数都必须大于基准值,因此我们把1放到下标为pos的位置上,同时把pos赋值为1的下标7,即pos = 7
然后我们从左边开始看,第一个数1小于key(3),符合基准值的概念,第二个数5大于key(3),不符合,因此我们就把5放到当前下标为pos的地方,同时pos也置为5的下标,即1。
此时发现右边的数都大于key值(3),左边的数都小于key值。那么我们就把key值放回下标为pos的位置上即可。
第一次循环结束 发现左边已经有顺序了 而右边还是比较乱 因此这里,我们用到了递归,递归调用本身来处理区间为[pos+1,right]的数组 ,(如果是左边无序,则是处理区间[left,pos-1],都乱的话那就都处理了)
注意:快速排序的循环中仅仅只是更换pos的值,而key值在此次循环中一直保持不变,直到找到自己合适的地方放入后。通过递归调用来更换下一个key值。
代码如下:
void quickArr(int arr[],int left,int right)
{
int pos = left; //left作为基准下标 使得基准左边皆小于基准,右边皆大于
int key = arr[pos];
int i=left;
int j=right;
while(j>i)
{
while(j>i && arr[j]>key)
{
j--;
} //循环找到右边小于key的值
if (j>i)
{
arr[pos] = arr[j];
pos = j;
}
while(j>i && arr[i]<=key) //=号放上面或下面都可以
{
i++;
} //循环找到左边大于key的值
if (j>i)
{
arr[pos] = arr[i];
pos = i;
}
}
arr[pos] = key;
if (pos-1 > left)
{
quickArr(arr,left,pos-1);
}
if (right>pos+1)
{
quickArr(arr,pos+1,right);
}
}
最后在封装一下就ok了
void quickSort(int arr[],int len)
{
quickArr(arr,0,len-1);
}
快速排序的时间复杂度为O(nlogn)
计算过程: T(n)=2T(n/2)+n n为第一次循环遍历所需 2T(n/2)表示递归所需的时间
T(n/2)=2T(n/4)+n/2 ..... 一直到T(2)= 2T(1)+2
可以得到T(n) = 2T(n/2)+n=4T(n/4)+2n=8T(n/8)+3n=.....=nT(1)+n*logn (T(1)为单位时间) 幂级数n小于nlogn 略去
得到时间复杂度为O(nlogn) log底数为2
最后
以上就是可靠鱼为你收集整理的排序算法02——插入排序(直接、折半)、快速排序的全部内容,希望文章能够帮你解决排序算法02——插入排序(直接、折半)、快速排序所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复