【排序一】插入排序
一、选择排序
1、基本思想
顾名思义,选择排序就是每次选一个数据放到其应该出现的位置,以升序(降序)为例,首先选最小(最大)的数据放到正确位置,接着再选次小(次大)的数据放到合适的位置,以此类推,直到最大(最小)的数据被放入最后一个位置,排序就算完成。
总体算法分三步完成:选数据--->将所选数据放入合适位置--->缩小需要排序的范围
图解(以升序为例):

2、排序效果图:

3、时间复杂度&&空间复杂度
选择排序的比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数:
N=(n-1)+(n-2)+...+1=n*(n-1)/2。
交换次数O(n),最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。
故此,选择排序的时间复杂度为O(N^2)。
选择排序的空间复杂度为O(1)。
4、实现代码
- #pragma once
- #include <iostream>
- #include <assert.h>
- using namespace std;
-
-
- void PrintArray(const int* a,const size_t n)
- {
- for (size_t i = 0; i < n; ++i)
- {
- cout<<a[i]<<" ";
- }
- cout<<endl;
- }
-
-
- void SelectSort1(int* a,size_t n)
- {
- assert(a);
- for (size_t i = 1; i < n; ++i)
- {
- int minIndex = i;
- int start = i - 1;
-
-
- for (size_t j = i+1; j < n-1; ++j)
- {
- if (a[j+1]<a[minIndex])
- {
- swap(a[j+1],a[minIndex]);
- }
- }
-
- if (a[minIndex] < a[start])
- {
- swap(a[start],a[minIndex]);
- }
- }
- }
-
-
- void SelectSort2(int* a,size_t n)
- {
- assert(a);
- int minIndex = 0;
- for (size_t i = 0; i < n - 1; ++i)
- {
- minIndex = i;
- size_t pos = i + 1;
-
- while(pos < n)
- {
- if (a[pos] < a[minIndex])
- {
- minIndex = pos;
- }
- ++pos;
- }
- swap(a[i],a[minIndex]);
- }
- }
-
-
- void SelectSort3(int* a,size_t n)
- {
- assert(a);
- int left = 0;
- int right = n - 1;
-
- while (left < right)
- {
- int minIndex = left;
- int maxIndex = right;
-
-
- for (int i = left; i <= right; ++i)
- {
- if (a[i] < a[minIndex])
- {
- minIndex = i;
- }
- if (a[i] > a[maxIndex])
- {
- maxIndex = i;
- }
- }
-
- swap(a[maxIndex],a[right]);
- if (minIndex == right)
- {
- minIndex = maxIndex;
- }
- swap(a[minIndex],a[left]);
-
- left++;
- right--;
- }
- }
-
- void TestSelectSort()
- {
- int a[] = {9,5,4,2,3,6,8,7,1,0};
- size_t sz = sizeof(a)/sizeof(a[0]);
-
-
-
- SelectSort3(a,sz);
- PrintArray(a,sz);
- }
运行结果:

二、堆排序
1、堆介绍
堆数据结构是一种数组对象,它可以被视为一棵完全二叉树结构。
堆结构的二叉树存储是:
(最)大堆:每个父节点的都大于孩子节点。
(最)小堆:每个父节点的都小于孩子节点。
如图所示:

2、堆排序的基本思想
堆积排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
1)将初始待排序关键字序列(R1,R2....Rn)
构建
成
大顶堆
,此堆为初始的无序区;
2)
将堆顶元素R[1]与最后一个元素R[n]交换
,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)
调整
为
新堆
,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
图解(假设为升序):

3、堆排序效果图

4、时间复杂度&&空间复杂度
假设一棵完全二叉树有N个节点,则它的的高度为lgN,堆排序中的比较次数为2*lgN,交换次数为N次,
故堆排序的时间复杂度为O(N*lgN)。
由于占用了有限个空间,所以堆排序的空间复杂度为O(1)。
5、代码实现
- #pragma once
- #include <iostream>
- #include <assert.h>
- using namespace std;
-
-
- void PrintArray(const int* a,const size_t n)
- {
- for (size_t i = 0; i < n; ++i)
- {
- cout<<a[i]<<" ";
- }
- cout<<endl;
- }
- void TestSelectSort()
- {
- int a[] = {9,5,4,2,3,6,8,7,1,0};
- size_t sz = sizeof(a)/sizeof(a[0]);
-
-
-
- SelectSort3(a,sz);
- PrintArray(a,sz);
- }
-
-
- void AdjustDown(int* a,size_t n,size_t pos)
- {
- size_t parent = pos;
- size_t child = parent*2 + 1;
- while(child < n)
- {
-
- if ((child+1 < n) && (a[child] < a[child+1]))
- {
- ++child;
- }
- if (a[child] > a[parent])
- {
- swap(a[child],a[parent]);
-
-
- parent = child;
- child = parent*2 + 1;
- }
- else
- {
- break;
- }
- }
- }
-
- void HeapSort(int* a,size_t n)
- {
- assert(a);
-
- for (int i = (n-2)>>1; i >= 0; --i)
- {
- AdjustDown(a,n,i);
- }
-
-
- for (int i = n-1; i > 0; --i)
- {
- swap(a[0],a[i]);
- AdjustDown(a,i,0);
- }
- }
-
- void TestHeapSort()
- {
- int a[] = {9,5,4,2,3,6,8,7,1,0};
- size_t sz = sizeof(a)/sizeof(a[0]);
-
- HeapSort(a,sz);
- PrintArray(a,sz);
- }
运行结果:
