插入排序:
插入排序的思路就是,前面的数组已经有序(从第二个数看来,第一个数已经有序了,它只要找到自己的插入点插入就行了;然后第三个数看前两个数都已经有序了....以此类推),下标为i的这个值依次与前面的值比较,找到合适的地方就可以直接插入了。但是,数组的插入是需要插入位以后的数据全部后移,所以我们边比较边移位,这样才能在找到合适位置的情况下直接插入。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20void 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)
上面的就是直接插入 ,对于直接插入我们发现效率不是很高,每次要找到插入点都需要遍历前面的部分数组,运气好第一个就是,运气不好要遍历全部。因此,折半插入做到了优化,每次都与有序数组(这里与上述一样)的中间值比较,如果值小于中间值,说明要插入的地方在中间值左侧,反之则在右侧。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26void 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值。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37void 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了
1
2
3
4void 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——插入排序(直接、折半)、快速排序内容请搜索靠谱客的其他文章。
发表评论 取消回复