1️⃣插入排序:把序列分为有序和无序两部分排序,如果是升序,则无序和有序比较小则有序右移直到找到大于有序值然后替换,大于则不变,有序++;继续比较;
主要用途:直接插入算法实现简单,在序列基本有序的情况下,移动和比较的次数少,所以有序情况下优先插入排序
复杂度与稳定度:属于稳定的排序方法,时间复杂度 O(n^2) 空间复杂度 O(1);
C/C++:
1 #include2 3 int *InsertSort(int *Array, int size) 4 { 5 if (Array == nullptr) 6 return nullptr; 7 8 //思想分为有序和无序部分 9 int unorder = 0, order = 0, temp;10 11 for (unorder = 1; unorder < size; unorder++)12 {13 //保存比较的值14 temp = *(Array + unorder);15 for (order = unorder - 1; order >= 0 && temp < *(Array + order); order--)16 {17 //升序,无序值小于有序值则有序值右移,直到找到比有序小的或order==0;18 *(Array + order + 1) = *(Array + order);19 }20 //不移动则赋值给自身,或者找到插入位置,赋值插入位置后的位置;21 *(Array + order + 1) = temp;22 }23 return Array;24 }25 26 27 int main()28 {29 30 int a[] = { 17, 46, 32, 87, 58, 9, 50, 38};31 int size = sizeof(a) / sizeof(int);32 InsertSort(a, size);33 34 std::for_each(std::begin(a), std::end(a), [](int &value)35 { std::cout << value << "\t"; });36 std::cout << std::endl;37 return 0;38 }
2️⃣折中插入排序:与插入排序的区别,寻找插入位置由从右到左遍历比较变为二分法查找比较(减少比较次数)
主要用途:同插入排序
复杂度与稳定度:同插入排序(虽然比较次数少了)
C/C++:
#include//折中插入排序,和插入排序的区别就是改变 无序在有序中查找位置的方式,前者是折中查找(减少比较次数),后者是从右到左遍历比较int *HalfInsertSort(int *Array, int size){ if (Array == nullptr) return nullptr; //思想分为有序和无序部分 int unorder = 0, order = 0, temp; //计算机中两数之和除以2取整之后值靠左(个人理解),(low+hight)/2 最终位置保存在low位置; int low = 0, hight = 0, mid = 0; for (unorder = 1; unorder < size; unorder++) { //保存比较的值 temp = *(Array + unorder); //寻找位置,终止条件位置出现负值之前- -,(升序) for (low = 0, hight = unorder - 1; hight >= low;) { mid = (low + hight) / 2; if (temp < *(Array + mid)) { hight = mid - 1; } else { low = mid + 1; } } //找到插入点low,移动 for (order = unorder - 1; order >= low; order--) { //升序,无序值小于有序值则有序值右移,直到找到比有序小的或order==0; *(Array + order + 1) = *(Array + order); } *(Array + low) = temp; } return Array;}int main(){ int a[] = { 17, 2, 3, 5, 4, 4, 34, 43, 323, 434, 234, 21, 46, 32, 87, 58, 9, 50, 38}; int size = sizeof(a) / sizeof(int); InsertSort(a, size); std::for_each(std::begin(a), std::end(a), [](int &value) { std::cout << value << "\t"; }); std::cout << std::endl; return 0;}
3️⃣希尔排序:是插入排序的改版,因为之前提到插入排序如果在序列有一定有序的情况比较次数会很少,所以希尔排序就是为增量为1的插入排序提供基本有序序列,
具体操作:先设定增量(一般序列size/2),例如10,增量规律5,2,1,然后根据增量间隔把序列分成增量个序列(如果按/2分增量,原数列是奇数序列的话会少选中一
个数,偶数列则 每个数都有归属分配的小数列,增量为1时肯定就都分配到了- -(以上只是个人blalala));
复杂度与稳定度:希尔排序是一种非稳定排序,由于增量是随机的,分析时间复杂度就比较困难当增量序列delta[k]=2^t-k+1 (其中,t为排序次数 1<=k<=t<<(以2为底n+1的对数)),
时间复杂度O(n^3/2),空间复杂度O(1);
C/C++:
1 #include2 3 4 //希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序, 5 //是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。 6 7 8 int *shellsort(int *Array, int size) 9 {10 int gap_value = 0;11 //外层循环控制增量以把序列分组12 for (gap_value = size / 2; gap_value > 0; gap_value /= 2)13 {14 //内层嵌套循环执行[直接插入算法],只是序列根据增量选择15 for (int unorde = gap_value; unorde < size; unorde++)//根据增量与序列长度 得当前增量下序列数16 {17 //实际直接插入比较,原来是右移查找,这里是交换停止来查找插入位置..18 for (int order = unorde - gap_value;19 order >= 0 && *(Array + order) > *(Array + order + gap_value); order -= gap_value)20 {21 //交换(突然想换异或交换- -,纯粹fun)22 *(Array + order) = *(Array + order + gap_value) ^ *(Array + order);23 *(Array + order + gap_value) = *(Array + order) ^ *(Array + order + gap_value);24 *(Array + order) = *(Array + order) ^ *(Array + order + gap_value);25 }26 }27 }28 29 return Array;30 31 }32 33 int main()34 {35 int s[] = { 1,2,3,4,5,6};36 37 shellsort(s, sizeof(s) / sizeof(int));38 39 for (int i = 0; i < sizeof(s) / sizeof(int); i++)40 {41 std::cout << s[i] << " ";42 }43 44 return 0;45 }
4️⃣冒泡排序:冒泡算法实现简单,适用排序元素较少,时间要求度不高的场合
复杂度和稳定度:冒泡排序是一种稳定的排序方式,时间复杂度0(n^2),空间复杂度0(1)
代码实例:代码中写了冒泡排序,双向冒泡排序,测试之后双向冒泡更快
C/C++:
1 #include2 3 //冒泡算法实现简单,适用于排序元素较少,时间要求度不高的场合 4 //复杂度与稳定度: 冒泡排序是一种稳定的排序方法,时间复杂度0(n^2),空间复杂度0(1) 5 6 7 void display(int* Array,int size); 8 9 int *BobolingSort(int *Array, int size) 10 { 11 if (Array == nullptr) 12 return nullptr; 13 int temp = 0; 14 for (int n = 1; n < size; n++) 15 { 16 for (int j = 0; j < size - n; j++) 17 { 18 if (*(Array + j + 1) < *(Array + j)) 19 { 20 temp = *(Array + j + 1); 21 *(Array + j + 1) = *(Array + j); 22 *(Array + j) = temp; 23 } 24 } 25 } 26 27 return Array; 28 } 29 30 31 32 int *DoubleBobolingSorot(int *Array, int size) 33 { 34 if (Array == nullptr) 35 return nullptr; 36 37 int i=0; 38 int low = 0, hight = size - 1; //正向遍历起点low,方向遍历起点hight 39 bool flag = true; //标志序列是否还有逆序 40 int temp = 0; 41 while (low < hight && flag) 42 { 43 flag = false; //设置0 44 for (i= low; i < hight; i++) //正向遍历 45 { 46 if (*(Array + i) > *(Array + i + 1)) 47 { 48 temp = *(Array + i); 49 *(Array + i) = *(Array + i + 1); 50 *(Array + i + 1) = temp; 51 flag = true; //有交换则true 52 } 53 } 54 hight--; //更新上界 55 56 57 for (i = hight; i > low; i--) 58 { 59 if (*(Array + i) < *(Array + i - 1)) 60 { 61 temp = *(Array + i); 62 *(Array + i) = *(Array + i - 1); 63 *(Array + i - 1) = temp; 64 flag = true; 65 } 66 } 67 68 low++; //更新下界 69 70 } 71 72 return Array; 73 } 74 75 void display(int* Array,int size) 76 { 77 for(int i=0;i
5️⃣快速排序:是冒泡排序的改进,也属于交换类排序,原理:①假设元素有N个,则选取第一个元素为枢轴pivot=Array[0],且low=0,hight=sizof(Array)/sizeof(int),
用i位置的pivot与hight比较,不小于则hight--向左推进,否则交换,从low++开始于pivot比较,大于则交换,hight--;否则推进,这样就完成
第一趟排序,小于pivot的在左边,大于的在右边,然后根据pivot的位置分成2序列,依照这个规律继续比较交换,直到low>=hight时则完成,
主要利用递归比较好运算(可是博主认为- -,这影响了效率);
复杂度与稳定度:是一种不稳定的排序方式,时间复杂度最坏0(n^2),平均时间复杂度0(nlogn),空间复杂度0(logn);
代码实例:与冒泡排序,双向冒泡排序,快速排序,运行时间比较同一序列排列1*10^7次数下的运行时间,双向运算比较快速- -,可能博主快排实现 太慢(导致运行速率慢);
1 #include2 3 4 //快速排序 5 6 void display(int* Array,int size) 7 { 8 for(int i=0;i =pivot)30 hight--;31 32 if (low < hight)33 {34 *(Array + low) = *(Array + hight);35 low++;36 }37 38 while (low < hight && *(Array + low) <=pivot)39 low++;40 41 if (low < hight)42 {43 *(Array + hight) = *(Array + low);44 hight--;45 }46 47 *(Array + low) = teamp;48 }49 50 51 52 return low;53 }54 55 void RecursiveQuickSort(int *Array, int low, int hight)56 {57 int pivot;58 59 if (low < hight)60 {61 pivot = QuickSort(Array, low, hight);62 RecursiveQuickSort(Array, low, pivot - 1);63 RecursiveQuickSort(Array, pivot + 1, hight);64 }65 66 }67 68 69 70 71 int main()72 {73 74 std::clock_t start=0,end=0;75 76 77 int test1[]={ 22,3364,23,44,32,66,45,666,88,88,23,4,5,6};78 79 80 start=clock();81 for(int i=0;i<10000000;i++)82 {83 RecursiveQuickSort(test1,0,(sizeof(test1)/ sizeof(int)-1));84 }85 end=clock();86 std::cout<<"RecursiveQuickSort runtime: "<<((double)(end-start)/CLOCKS_PER_SEC)<
C/C++:三种排序方法运行时间比较
1 #include2 3 4 //快速排序 5 6 void display(int* Array,int size) 7 { 8 for(int i=0;i =pivot) 50 hight--; 51 52 if (low < hight) 53 { 54 *(Array + low) = *(Array + hight); 55 low++; 56 } 57 58 while (low < hight && *(Array + low) <=pivot) 59 low++; 60 61 if (low < hight) 62 { 63 *(Array + hight) = *(Array + low); 64 hight--; 65 } 66 67 *(Array + low) = teamp; 68 } 69 70 71 72 return low; 73 } 74 75 void RecursiveQuickSort(int *Array, int low, int hight) 76 { 77 int pivot; 78 79 if (low < hight) 80 { 81 pivot = QuickSort(Array, low, hight); 82 RecursiveQuickSort(Array, low, pivot - 1); 83 RecursiveQuickSort(Array, pivot + 1, hight); 84 } 85 86 } 87 88 int *DoubleBobolingSorot(int *Array, int size) 89 { 90 if (Array == nullptr) 91 return nullptr; 92 93 int i=0; 94 int low = 0, hight = size - 1; //正向遍历起点low,方向遍历起点hight 95 bool flag = true; //标志序列是否还有逆序 96 int temp = 0; 97 while (low < hight && flag) 98 { 99 flag = false; //设置0100 for (i= low; i < hight; i++) //正向遍历101 {102 if (*(Array + i) > *(Array + i + 1))103 {104 temp = *(Array + i);105 *(Array + i) = *(Array + i + 1);106 *(Array + i + 1) = temp;107 flag = true; //有交换则true108 }109 }110 hight--; //更新上界111 112 113 for (i = hight; i > low; i--)114 {115 if (*(Array + i) < *(Array + i - 1))116 {117 temp = *(Array + i);118 *(Array + i) = *(Array + i - 1);119 *(Array + i - 1) = temp;120 flag = true;121 }122 }123 124 low++; //更新下界125 126 }127 128 return Array;129 }130 131 132 133 int main()134 {135 136 std::clock_t start=0,end=0;137 138 139 int test1[]={ 22,3364,23,44,32,66,45,666,88,88,23,4,5,6};140 int test2[]={ 22,3364,23,44,32,66,45,666,88,88,23,4,5,6};141 int test3[]={ 22,3364,23,44,32,66,45,666,88,88,23,4,5,6};142 143 144 start=clock();145 for(int i=0;i<10000000;i++)146 {147 BobolingSort(test3,(sizeof(test3)/ sizeof(int)));148 }149 end=clock();150 std::cout<<"Simple Bob runtime: "<<((double)(end-start)/CLOCKS_PER_SEC)<
5.简单选择排序:是一种不稳定的排序方法,通过递归找到最小或者最大元素位置,并与首元素交换,这样,完成第一趟排序,之后亦然,index相同则不交换,总需要元素数n-1趟排序,比较次数不定(查到的是需要3(n-1)/2次比较,可是我认为这应该是不确定的啊),最多3(n-1)次移动数值,而最好呈有序则不需排序,最坏都要排序
复杂度与稳定度:不稳定排序,时间复杂度O(n^2),空间复杂度O(1)
C/C++代码:
1 #include2 3 4 int * 5 selectsort(int *Array, std::size_t size) 6 { 7 if (Array == nullptr) 8 { 9 return nullptr;10 }11 12 std::size_t index = 0;13 14 for (int i = 0; i < size; i++)15 {16 index = i;17 18 for (int j = i+1; j < size; j++)19 {20 if (*(Array + index) > *(Array + j))21 {22 index = j;23 }24 }25 26 if (index != i)27 {28 std::swap(*(Array + index), *(Array + i));29 }30 31 }32 33 return Array;34 }35 36 37 void38 display(int *Array, int size)39 {40 for (int i = 0; i < size; i++)41 {42 std::cout << *(Array + i) << "\t";43 }44 45 std::cout << std::endl;46 }47 48 49 int50 main(int argc, char **argv)51 {52 53 54 int test1[] = { 22, 3364, 23, 44, 32, 66, 45, 666, 88, 88, 23, 4, 5, 6};55 56 selectsort(test1, sizeof(test1) / sizeof(int));57 display(test1, sizeof(test1) / sizeof(int));58 return 0;59 }
6.堆排序:选择排序的改进版本(各种改进qwq), 概念上的二叉树,实际操作的是数组,利用二叉树的思维创造数组树,根据规则每个元素a[i]可以有lnode=a[2*i+1],rnode=
a[2*i+2]这样的约束,分为两部分,初始化大/小顶堆,调整大/小顶堆,而 初始化大/小顶堆操作 依赖 调整大/小顶堆操作,初始化大/小顶堆需要从最后一个非叶子结点开始,根据约束向上创建顶堆,得出第一个最大/最小元素,之后可以pop最大或最小元素(例子中,是替换尾部元素),从尾部填充根节点,缩小范围从0~尾部向下调整顶堆,使新极值替换到根节点- -,大概这样
时间复杂度和空间复杂度:时间复杂度O(nlogn^2),空间上 O(1);
C/C++代码:
1 #include2 #include 3 4 5 void 6 adjustheap(int *, std::size_t, std::size_t); 7 8 void 9 createheap(int *Array, std::size_t length) 10 { 11 if (Array == nullptr) 12 { 13 return; 14 } 15 16 17 //建立大顶堆 18 //先从第一个非叶子结点开始,向上建立堆 19 for (int i = length / 2 - 1; i >= 0; --i) 20 { 21 adjustheap(Array, i, length - 1); 22 } 23 24 25 } 26 27 //调整大顶堆 28 void 29 adjustheap(int *Array, std::size_t node_p, std::size_t length) 30 { 31 if (Array == nullptr) 32 { 33 return; 34 } 35 36 //保存当前根节点值 37 int t = *(Array + node_p); 38 39 for (int i = 2 * node_p + 1; i <=length; i = i * 2 + 1) 40 { 41 //先判别左右子节点大小,确定与根节点比较对象,小于则更i++ 42 if (i < length && (*(Array + i) < *(Array + i + 1))) 43 { 44 i++; 45 } 46 47 48 //与当前根节点比较 49 if (t > *(Array + i)) 50 { 51 break; 52 } 53 54 //小于则交换 55 *(Array + node_p) = *(Array + i); 56 node_p = i; 57 //保存交换过的位置,为了向下寻找是否还有小于 根节点值得节点以让根节点赋值 58 } 59 60 *(Array + node_p) = t; 61 62 } 63 64 void 65 display(int *Array, std::size_t length) 66 { 67 68 if (Array == nullptr) 69 { 70 return; 71 } 72 73 74 for (int i = 0; i < length; i++) 75 { 76 std::cout << Array[i] << std::setw(4); 77 } 78 79 std::cout << std::endl; 80 81 } 82 83 84 void 85 sortheap(int *Array, std::size_t length) 86 { 87 if (Array == nullptr) 88 { 89 return; 90 } 91 createheap(Array, length); 92 93 std::cout << "初始化大顶堆: "; 94 display(Array, length); 95 96 //循环把大顶堆根节点与尾节点交换 97 for (int i = 1; i =a[2*i+1]&&a[2*i+2] 性质,可从0~未替换尾部元素之间检查顶堆规则108 adjustheap(Array, 0, length - i-1);109 }110 111 112 }113 114 115 int116 main(int argc, char **argv)117 {118 int test[] = { 4, 2, 3, 4, 5, 6, 7, 8, 9, 10};119 120 sortheap(test, sizeof(test) / sizeof(test[0]));121 122 return 0;123 }