이 문서에서는 일곱 일반적인 정렬 알고리즘뿐만 아니라, 자신의 원칙 및 성능 분석 C 언어를 설명합니다 :
일관성, 사용하려면 모든 알고리즘을 모두 오름차순으로 정렬 본원 해석
우선 [] 무질서한 배열 요소의 도착을 준비 배열 길이의 길이, 스왑 함수 스왑
구현은 기본 기능에 정렬 함수를 호출하고 출력 결과를 정렬 :
보이드 스왑 (INT * X, INT * Y) {
INT 온도 = * X;
* * X = Y;
* Y = 온도; } 값 int () {메인 INT의 도착 [] = {1,8,5,7,4,6,2,3 }; INT = 길이를 sizeof (도착) /를 sizeof (INT ); 종류 (편곡, 길이); 대해 INT (I = 0; I <길이; I ++ ) {printf와 ( "% D \ n" , 도착 [I]); } 0을 반환 ; }
삽입 정렬
첫 번째주기 :
두 번째주기 :
세 번째주기 :
외부 루프의 각 실행 무질서 영역에서 도착 순서로 데이터 영역에 삽입된다 [I]
데이터는 이전보다 더 작은 경우, 루프 제어에 삽입 된 레이어 데이터가, 언 [I]는 그 직전의 데이터 비교의 전과 변화 후 데이터하자
다음과 같은 데이터를 이동 한 후에 도착 등 ... 도착보다 찾을 때까지 상기 단계를 반복하는 [I] 도착 소형 데이터 [J], [J]를 직접적 [I]에서, 언 자유 도착 [J + 1] 위치
C 프로그램 구현 :
보이드 CRsort (INT의 도착 [], INT 길이) {
INT 온도;
경우 (나는 <길이; INT 나 0 = I ++ ) {
임시은 = [I], 언; 대 (INT J = I - 1; J> = 0; j-- ) { (도착 [J]> 만약 온도) {도착 [J + 1] = 도착 [J] 사용한다} else {도착 [J + 1] = 온도; 휴식 ; }}}}
성능 분석
안정성 : 안정
-> 내부 루프 실행 후, 도착 만 동일 할 것이다 [I] 시프트 도착 이상 발생 [I]는 변화되지 않는다
시간 복잡도 (최악 n², 바람직하게는 N, 평균 N²)
-> 데이터의 양이 N이고, n은 데이터가 정렬되면 회 외부 루프는 n 배의 최대 내부 루프 만 내부 루프를 실행할
더 순차적 데이터, 높은 효율의 삽입 정렬
우주의 복잡성 : 1
-> 재귀를 사용하지 않는 프로그램, 임시 변수는 스토리지 자원, 하나의 복잡한 공간을 차지하지 않는다
쉘 정렬
쉘 정렬, "증가 종류의 확대"라는 향상된 삽입 정렬 현재 행입니다 :
삽입 정렬 장점 단점 힐 정렬이 두 특성을 이용하여, 하나의 소자 각각 비교 한 근접 정렬 요소를 처리하기에 적합하다 :
통상 삽입 정렬 달리 셸 정렬 가지고 점진적 시퀀스 R 일반적으로, R의 초기치 및 INT (길이 / 2) 2 라운드 다운 나눈 요소 즉 수가
모든 단위는 떨어져 요소 그룹은 그룹의 순서를 수행 r에
모든 바이너리 증가는 마지막 종류까지, 하나의 단위로, 다음 요소는 주문해야합니다
델타 최 외측 루프 제어 그룹, 즉, 각 사이클 증분
루프 내부에는 두가지 기본 삽입 일종이지만, 각각의 부가를 순서화 된 세트 도착하지 [I + 1] 그러나 도착 [I + 델타]
C 프로그램 구현 :
보이드 셸 정렬 ( INT의 도착 [], INT 길이) { INT를 R, 온도, J; 대 (길이 = R / 2 , R> = 1 , R = R / 2 ) { 대 ( INT I = R; I <길이; I ++ ) { 임시 =은 [I], 언; J는 I를 = - (R)를; 반면 (j> = 0 && 온도 < 도착 [J]) { , 언 [J + R = 도착 [J] J는 J가 = - (R)를; } 도착 [J + R = 온도; } } }
성능 분석
안정성 : 불안정한
-> 각 요소 자체 정렬 기이고, 두 그룹의 다른 요소에 대해 동일한 값이 다를 수 전체적인 상대 위치를 정렬
시간 복잡도 : (최악의 n², 바람직하게는 N, 평균 N ^ 1.3)
-> 정렬 분석 셸은 시간 인터넷에서 촬영 미해결 수학 문제의 수를 포함한다 "증분"연속 촬영 기능을인지, 복잡한 문제이다.
데이터가 정렬되면 바람직하게는 동일한 일반적인 삽입 정렬 만 내부 루프를 실행할
주문 데이터의 실행의 높은 효율 : 또한 정렬 삽입의 특성을 갖는다
우주의 복잡성 : 1
-> 재귀를 사용하지 않는 프로그램, 임시 변수는 스토리지 자원, 하나의 복잡한 공간을 차지하지 않는다
버블 정렬
버블 정렬
외부 루프 요소마다 정렬 영역을 배치
내측 루프 제어 요소로 : 설정 포인터 j는, [J]의 값을 가지고 도착 [J + 1], 언 비교 :
만일 도착 [J] <도착 [J + 1] 장애 비교 완료까지 ++ [J]와, 언 값 [J + 1] 과거 또는 J를, 언 것
이 버블 정렬을 최적화 할 수 있음을 언급 할만큼 가치입니다 :
변경 세트가있을 때 상태 코드 변경 설정, 데이터 교환이 일어난다
당신이 정렬 교환이 일어나는 풀 타임이없는 경우,이는 직접 사이클을 종료 할 수 있습니다, 데이터의 정렬 된 세트입니다
C 프로그램은 달성하기 위해 :
INT MPsort (INT 도착 [], INT의 길이) {
INT 온도 변화 = 0 ;
경우 (나는 <길이; INT 나 0 = I ++ ) {
for (int j = 0;j < length - i - 1;j++) {
if (arr[j] > arr[j + 1]) {
swap(&arr[j],&arr[j+1]); change = 1; } } if (change == 0) { return 0; } } }
性能分析
稳定性 : 稳定
-->数据只有在大于或小于时才会交换,相等时不会交换,因此相同数据的相对位置不会发生改变
时间复杂度 : (最坏n²,最好n,平均n²)
-->在数据完全有序时,不会有数据交换,根据上面的优化处理,状态码change不会改变,外层循环执行一次就结束,时间复杂度为n+1,也就是n.
而如果是非常无序的数据,外层循环执行满n次,时间复杂度就是n²
空间复杂度: log(2)(N)
-->程序没有用到递归,临时变量不占用存储资源,因此空间复杂度为1
快速排序
快速排序是一种效率比较高的排序方法,这张图片我认为介绍的很清楚,搬运来用一下,出处在文章下面:
c程序实现:
void KSSort(int arr[], int left, int right) {
if (left < right) {
int key = arr[left];
int l = left;
int r = right;
while (l < r) { while (l < r && arr[r] >= key) { r--; } if (l < r) { arr[l] = arr[r]; l++; } else { break; } while (l < r && arr[l] <= key) { l++; } if (l < r) { arr[r] = arr[l]; r--; } else { break; } } arr[l] = key; KSSort(arr, left, l - 1); KSSort(arr, l + 1, right); } }
性能分析
稳定性 : 不稳定
--> 假设是稳定的,举个反例:
5 | 3 1 2 | 9 7 8 9 | 4 6 3
这时遍历unvisited部分 刚到了4 (array[8])
显然4<5 ,这是4应该从 unvisited 部分去到 lower 部分。 因此 higher部分第一个元素 9 (array[4]) 和 4互换。变成了这样:
5 | 3 1 2 4 | 7 8 9 9 | 6 3
时间复杂度 : (最坏n²,最好nlogn,平均nlogn)
-->快速排序最差的情况就是每次取到的基准数baes都是排序组的边界值(不是最小的就是最大的),这时外层循环要遍历n次才能将所有数据比较完,时间复杂度就是n²
这种情况多发生在排好序(或接近排好序)的数据中,要在这种数据中避免使用快速排序算法
最好的情况是基准数每次都能取到接近排序组的中位数,用最短的循环次数将程序完全分割,n个数据每次减半,也就是log(2)(N)次后数据被完全分割,算法的时间复杂度为
最差的情况不容易取到,平均时间复杂度取nlogn
空间复杂度: logn
-->在我这个程序里没有用到递归,空间复杂度为1,当然也可以使用递归实现,递归log(2)(N)次,空间复杂度为logn
最后附一张各种排序算法比较图
选择排序
选择排序是最简单的排序方式,也是比较低效的一种排序方式:
第一次循环 :
第二次循环:
第三次循环:
外层循环每执行一次向有序区添加一个元素
内层循环遍历到最大的元素,与刚刚填入有序区的元素交换
......直到数据全部加入有序区
c程序实现:
void XZsort(int arr[] , int length) { int check; for (int i = 0;i < length - 1;i++) { check = i; for (int j = i + 1;j < length;j++) { if (arr[j] < arr[check]) { check = j; } } if (i != check) { swap(&arr[i],&arr[check]); } } }
性能分析
稳定性 : 稳定
-->存在两个相同的元素时,肯定是下标小的元素先进入有序区,而且在值相等的情况下有序区元素不会被替换
时间复杂度 : (最坏n²,最好n²,平均n²)
-->外层循环要执行n次,才能将n个数据全部加入有序区
无论数据是否有序,内层循环都要将所有的数据比较一遍,找到最小的元素
空间复杂度: 1
-->程序没有用到递归,临时变量不占用存储资源,因此空间复杂度为1
堆排序
堆排序是选择排序的改进版本,它比堆排序的性能要高很多.
要实现堆排序,首先要了解这几个知识点:
大根堆:每个节点的值都大于他的左右子树(小根堆反之)
完全二叉树:除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐。
在n个节点的完全二叉树中,叶子节点有(n+1)/2个,非叶子节点有(n-1)/2个
在堆中,下标为n的数的左子树为2n+1,右子树为2n+2
首先要能够将一组无序的数排列成大根堆,大根堆的构造方法如下:
...
外层循环从最后一个非叶子节点( length/2-1 )向根节点遍历,每遍历到一个数据,就执行下面操作:
设置一个根指针i,指向当前要操作树的根节点
比较该树的左右子树的值,将biger指针指向较大的子树
如果该子树的值比根节点还大(arr[biger]>arr[i]),将该子树的值与根节点交换,并将i指针指向该子树,使之成为新的根节点
......递归执行上一步操作,直到有根节点不小于左右子树为止
构造出大根堆之后,每次取整个堆的根节点(也就是第一个元素)存入有序区,将堆的最后一个元素作为根节点
剩下的元素继续构造大根堆,直到数据完全存入有序区
c程序实现:
void MkHeap(int arr[], int i, int length) { int bigger = 2 * i + 1; int temp; if (bigger<length){ if (arr[bigger] < arr[bigger + 1]) { bigger++; } if (arr[i]<arr[bigger]){//如果子树比爹树大:把子树的值与爹树值交换,并让该子树成为新的爹树 swap(&arr[i], &arr[bigger]); MkHeap(arr,bigger,length); } } } void HeapSort(int arr[], int length) { //从最后一个非叶子节点往根找 for (int i = length / 2 - 1;i >= 0;i--) { MkHeap(arr, i, length); } for (int j = length - 1;j > 0;j--) { swap(&arr[j],&arr[0]); MkHeap(arr, 0, j-1); } }
性能分析
稳定性 : 不稳定
-->先假设稳定,然后举个反例:
{6,7,7}这棵树左右子树的值都是7,本来左子树是应该是在前面的,但是6加入有序区之后右子树的7会被提到最上面,这样他们的顺序就被调换了
时间复杂度 : (最坏nlogn,最好nlogn,平均nlogn <底数可以写2也可以不写,根据时间复杂度的性质无论底数是几结果都是一样的> )
-->根据性质,外层循环会执行n次(n代表排序的元素个数),将所有数据全部加入有序区.
而内层递归函数指针从0到n,每次增长前一个的2n+1,忽略掉常数1,也就是执行log(2)(N)次
因此为Nlog(2)(N)次,忽略掉底数2,时间复杂度为nlogn
插入/希尔排序适合接近有序的数据,而堆排序适合非常无序的数据,因为无论数据多么杂乱,希尔排序的时间复杂度都是nlogn
(不放心再说一下 : log(2)(N)是log以2为底n的对数 , 不是log2乘n , 因为底数打不出来只能这样写)
空间复杂度: log(2)(N)
-->这里程序递归了log(2)(N)次,每次递归都占用内存,因此空间复杂度为log(2)(N)
当然也可以使用循环的方式实现,但是那样写出来结构略显混乱,不如递归方式清晰
不稳定算法口诀:快些选队
参考资料(文中的部分图片和思想来自以上材料):
1. 《新编数据结构习题与解析》
2. 文章
https://www.cnblogs.com/skywang12345/p/3603935.html
https://www.cnblogs.com/jingmoxukong/p/4302891.html
http://www.sohu.com/a/341037266_115128
https://www.toutiao.com/a6593273307280179715/?iid=6593273307280179715
3. 关于快速排序算法的稳定性? - 知遥其实是德鲁伊的回答:https://www.zhihu.com/question/45929062/answer/262452296