详细代码及分析见(6/7)部分程序测试及运行结果: 1.直接插入排序 2.起泡排序 3.希尔排序 4.快速排序 5.简单选择 |
我对于插如排序的理解就是,将一个待排序的元素插入到前面已经排好序列中,直到全部排好。 比如随便一组元素: 24 16 49 35,我把24单独看成一个已经排好的序列。 第一次排序把16插入到24这个序列中,也就是用16和24比较,16小,就是16往左移,则序列变成16 24, 第二次排序再用49和序列右边第一个比较,49大,则放在序列右边。序列就变成了16 24 49。 第三次排序把35与49比较,发现35小,则左移动一位,35比24大。则序列就成型为16 24 35 49 对此我发现对于n个元素我们需要进行n-1次的排序 我依照这个规律编写了如下的代码: void zhi_jie_cha_ru(S *L) { int i, j; for (i = 2; i <= L->len; i++) { if(L->data[i].key < L->data[i - 1].key) { L->data[0].key = L->data[i].key; for (j = i - 1; L->data[0].key < L->data[j].key; j--) L->data[j + 1] = L->data[j]; L->data[j + 1] = L->data[0]; } } } 其中关键语句分析如下:for (i = 2; i <= L->len; i++) 中L->len表示元素的长度,i就表示执行排序的次数。 至于(L->data[i].key < L->data[i - 1]. Key这条语句L->data[i].key代表的就是我们正在排序的那个元素比如上面讲的那个第二次排序(i=2)时序列其实为16 24 49 35. L->data[i].key也就是49,而data[i - 1]. Key就是前面排号序列最大的一个或者是说,是49后面一个。 而L->data[0].key则是我引入的中间变量,如果L->data[i].key < L->data[i - 1].key则把L->data[i].key的值赋给 L->data[0].key 同理再引入一个循环也就是for (j = i - 1; L->data[0].key < L->data[j].key; j--)如果我们进行排序的那个值依然小于排好序列的第二大的值则依然进行这个循环,一直到再排好的序列中找到了比我们进行排序的数(也就是L->data[i].key)小的数,此时循环再结束。(也可以理解为这个循环时为了找到插入的位置)找到位置以后就进行最后一步L->data[j + 1] = L->data[j];和L->data[j + 1] = L->data[0];其中我们找到的位置就是L->data[j + 1]所在的位置 然后再将L->data[0]的值赋给它,就完成了排序。 最后我总结,由于里面使用了for语句的嵌套,所以它的时间复杂度也就是O(n^2),并且它是稳定的。
2.希尔排序: 我对于希尔排序的理解就是,先确定一个增量,然后把相邻这个增量的元素组成一个子表,然后对这个子表进行直接插入排序,当整个表基本有序的时候,我们就整体进行一次直接插入排序。也可以理解为增量为1。 比如我以我的学号为例子构造这几个元素,20 2 04 09 12 32 比如确定增量为2,也就是20然后再往后数两个,也就是04,再往后就是12(再往后就没有了)所以20 04和12是一个子表就,对其进行第一次排序直接插入排序变成 04 2 12 09 20 32 同理再从2开始往后数两个,也就是2 09 32构成一个子表 第二次排序后为 04 2 12 09 20 32 此时就已经时就已经是基本有序了,对此再进行整体进行直接插入排序 就为 2 04 09 12 20 32我们就完成了希尔排序。 我依照这个规律同样编写了如下的代码: void Xi_er(Elemtype data[], int length, int delta) { int i, j; for(i=1+delta;i<=length;i++) if(data[i].key > data[i - delta].key) { data[0] = data[i]; for (j = i - delta; j > 0 && data[0].key > data[j].key; j -= delta) data[j + delta] = data[j]; data[j + delta] = data[0]; } } 我从刚才自己学号举例看出知道这 个算法是不稳定的(因为有元素的相对位置发生了改变),而这个代码的增量的值是不知道的所以两个for循环次数也无法确定所以时间复杂度是无法确定的。 3.主函数:对于主函数就十分简单了,用了我的姓名首字母‘cj’定义成选择使用的排序方法,然后用printf编写简单的界面。最后利用switch函数来使用需要调用的函数。这些都是c语言最基础的知识,所以不用赘述 void main() { int cj; printf("请你输入要排序的元素个数:\n"); scanf("%d",&n); L.len = n; printf("请输入想要使用的方法:\n"); printf("1.直接插入排序"); printf("2.起泡排序"); printf("3.希尔排序"); printf("4.快速排序"); printf("5.简单选择排序"); scanf("%d",&cj); printf("你选择的是第%d种方法:",cj);
suijishengchengshu(); jishi(); switch (cj) { case 1: { zhi_jie_cha_ru(&L); printf("直接插入排序结果为:\n"); shu_chu(L); }break; case 2: { qi_pao(&L); printf("起泡排序排序结果为:\n"); shu_chu(L); }break; case 3: { Xi_er(&L ,A,9); printf("希尔排序结果为:\n"); shu_chu(L); }break; case 4: { Kuai_su(&L, 1, 9); printf("快速排序结果为:\n"); shu_chu(L); }break; case 5: { Jian_dan_xuan_ze(&L); printf("简单选择排序结果为:\n"); shu_chu(L); }break; } printf("\n"); system("pause"); } 4.各种排序的总结心得: 查阅资料让我知道,每个排序都有自己优缺点,但是平均最优算法是快速排序。 对于直接插入排序、冒泡排序、简单选择排序的平均时间复杂度都是O(n^2),而快速排序、堆排序(学艺不精未能实现代码)平均时间复杂度都是为O(n*Iog2^n),至于希尔排序的时间复杂度是不能确定的。 而对于空间复杂度(也就是储存的内存空间大小),上述的排序中除了快速排序为O(n*Iog2^n)其他(直接插入排序、希尔排序、冒泡排序、简单选择排序、堆排序)都为O(1) |
c语言/c++(数据结构篇) 之 排序方法的实现分析(直接插入排序;冒泡排序;希尔排序;快速排序;简单选择排序)(7/7)
最新推荐文章于 2023-09-16 22:06:24 发布