从零开始_学_数据结构(六)——排序(冒泡、插入、希尔、简单选择、归并、快速)...
一、冒泡排序:
(1)思想是:
从第1个开始,1和2比,2和3比,3和4比,如果前面比后面大,则互相交换之,一直到n-1和n进行比。这是第一轮。
然后第二轮再从第1个开始,2和3比,3和4比,再一直比到n-1和n,比的时候符合条件(前大后小)则交换。
然后一直到从n-1个开始,最后比较一次n-1和n。
因此,时间复杂度是O(n2);
代码:
#include<iostream>void maopao()
{using namespace std;int n = 100;int m[100];for (int i = 0; i < n; i++)//赋值,从m[0]到m[99],值是100->1m[i] = 100 - i;for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";cout << "————分割线————" << endl;for (int i = 0; i<n; i++) //排序for (int j = 0; j<n - 1; j++){if (m[j]>m[j + 1]){int temp;temp = m[j];m[j] = m[j + 1];m[j + 1] = temp;}}for (int i = 0; i < n; i++)//显示当前排序cout << m[i] << " ";
}
二、插入排序:
(1)其思想是:
①首先,给最左边留一个空(用于临时存储要被移动的数字),例如a[0]
②然后从右往左开始比;例如从a[1]开始
③假如当前值a[3]比其左边的大,进入判断,否则继续下一个数字;
④假如当前数值比左边的小,于是,把当前值给最左边预留的空位(a[0]);
⑤然后进入循环,问,现在这个位置(第j位)值,是不是是比左边的小,如果小,将左边的值赋给他(而他的值目前在a【0】处),然后当前位置(j)往左移动一位(j--)并且再一次判断,移动后的这个位置,其值是不是比左边的值小,如果小,执行相同的指令;
⑥假如当前位置的值比左边的大了,于是终止循环,由于记录了终止循环时的位置(此时的位置的值,要么是完全没有交换,要么是把当前位置的值赋给了他右边的位置),因此,把之前存储在a【0】位置的值,赋给他(无论是哪种情况都不影响)。
⑦因此,只要被排序过的,一定是小的在左边,大的在右边(大的都被移动到右边去了),等排序完了,整体数组一定是小的在左边,大的在右边了。
代码:
void charu() //插入排序
{using namespace std;int n = 100;int m[100];for (int i = 0; i < n; i++)//赋值,从m[0]到m[99],值是100->1m[i] = 100 - i;for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";cout << "————分割线————" << endl;for (int i = 1; i < n; i++){int temp = m[i]; //临时存放这个m[i](插入的数字)int j = i; //记录j=iif (j>0 && m[j] < m[j - 1]) //首先j要>0(防止出界),然后插入这个位置比左边位置的小while (temp < m[j - 1] && j>0) //开始循环,将左边放到右边,直到左边的比右边小m[j--] = m[j - 1]; //每次交换后,都要往左移动一位(即第一次是交换n-1和n,第二次就是n-2和n-1)m[j] = temp; //此时j的位置被赋值(即插入的位置,右边都比他大,左边也比他小)}for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";
}
三、希尔排序:
相当于连续多次的插入排序(但比插入排序优化)
时间复杂度是f(n)=n log n;(比n2要小)
代码:
//希尔排序for (gap = length / 2; gap > 0; gap /= 2) //每次步长减半{for (i = 0; i < gap; i++) //步长有多少,就移动多少次{for (j = i + gap; j < length; j += gap) //以步长为间距进行交换,注意,初始位置是i位置加步长的位置(即第二步){if (m[j] < m[j - gap]) //当前位置和其步长位置之前的进行比较(以步长为间距)。第一次是第二步和第一步进行比较{int temp = m[j];int k = j - gap; //两个数字的位置差,k是第一步的位置while (k >= 0 && m[k]>temp) //k>0说明在右边,要交换的位置在右边。第二个指第一步比临时存储第二步大(所以需要交换,否则第一步比第二步小则不用交换){m[k + gap] = m[k]; //当前位置和右边的交换k -= gap; //然后往左移动一个步长(同组的左边那个)}m[k + gap] = temp; //将存储在临时的,赋值给移动后最左边的位置}}}}
四、简单选择排序
(1)思想:
从第1个开始,然后先看第2个是否比第一个小,是则交换然后继续,不是则继续。然后再看第3个是否比第一个小,判断是否交换,再看第4个,以此类推。一直到第n个。——因此,可能比较了n-1次,但是0次交换(说明排序前,该位置是没问题的),也可能是若干次交换,但无论如何,当比较n-1次后,该位置的数字就是它应该的数字。
然后从第2个开始,依次比较3、4、5...一直到第n个。
总比较次数是(n-1+1)*(n-1)/2次
(2)时间复杂度:
f(n)=O(n2);
(3)代码:
int n = 100;int m[100];for (int i = 0; i < n; i++)//赋值,从m[0]到m[99],值是100->1m[i] = 100 - i;for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";cout << "————分割线————" << endl;for (int i = 0; i < n-1; i++) //第i轮,总计n-1轮for (int j = i; j < n; j++) //第i轮中的循环{if (m[j] < m[i]) //后面比前面小则交换{int temp;temp = m[j];m[j] = m[i];m[i] = temp;}}for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";
五、归并排序
(1)思路:
首先,将数组对半分拆,放入1个新数组之中(分为前后两部分);
使用递归,分别对分拆后的数组(前后某个部分)继续分拆,放入一个更新的数组之中(分为前后两部分),此时,这个更新的数组,长度和旧的是一样的(但由于递归,每次占用的相对于总长度而说越来越少);
一直到对半分后为1个的情况下,将其放入相对较旧的那个数组对应的位置之中。
然后递归返回,开始排序。
此时,是有一较旧数组和一较新数组,有较新数组使用的初始下标、中间下标和结束下标(以中间为分割,分为前后两部分)。
然后对较新数组的前后两部分进行排序,放入较旧的数组之中。
继续递归返回,此时较旧数组作为较新数组,和另外一个较新数组一起属于一个较新数组的前后两部分,然后通过排序,放入较旧数组之中。
一直递归到初始数组为止。
然后新数组就是排序好的。
(2)代码:
int n = 100;int m[100];for (int i = 0; i < n; i++)//赋值,从m[0]到m[99],值是100->1m[i] = 100 - i;for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";cout << "————分割线————" << endl;int*p = new int[n];guibing(m, p, 0, n-1);for (int i = 0; i < n; i++) //显示当前排序,这里要输出新数组p的cout << p[i] << " ";delete[]p; //删除(如果需要保留则不删除)void guibing(int *old, int *ne, int first, int last) //旧数组old(没排序的),新数组ne(排序好的),first(数组第一个元素),数组的最后一个元素的下标
{int middle;int *ne2 = new int[last + 1]; //ne2的长度是数组总长if (first == last) //如果相等,说明数组第一个元素就是最后一元素ne[first] = old[first]; //将没排序的放到排序好的那个数组对应的位置else{middle = (first + last) / 2; //寻找中间的坐标guibing(old, ne2, first, middle); //把guibing(old, ne2, middle + 1, last);caozuo(ne2, ne, first, middle, last);}delete[]ne2;
}
void caozuo(int*ne2, int*ne, int i, int m, int n)
{int j, k, l;for (j = m + 1, k = i; i <= m&&j <= n; k++) //j是后半部分数组的起始下标,k是前半部分数组的起始下标,当前半部分下标i比m大,或者后半部分下标比n大则结束循环{if (ne2[i] < ne2[j]) //如果较新数组的后半部分位置j比前半部分对应数组位置k大ne[k] = ne2[i++]; //把小的那个放入较旧的数组的k位置(之后k+1),并且小的那个移动到下一个位置elsene[k] = ne2[j++]; //同上}//此时,前后部分必然有一部分复制完,另外一部分剩1个或者更多if (i <= m) //如果前面的没有复制完,则复制完{for (l = 0; l <= m - i; l++)ne[k + l] = ne2[i + l];}if (j <= n){for (l = 0; l <= n - j; l++)ne[k + l] = ne2[j + l];}
}
六、快速排序
(1)思想:
①先用第一个元素,作为比对值key。
②然后从后面开始找,如果有比key小的,交换之(key到后面);
③然后再从前面找,有比key大的,和key交换,(key又到前面);然后再从后面找,②③循环,直到前后相遇
④于是前后相遇的地方为中间值,返回其下标。
此时,这个下标前面的必然比他小,后面的必然比他大。原因是数组中每个数他都比较过了,并且把比他小的通过交换放他前面了,比他大的放他后面了。
⑤以下标为中心,分为前后两部分(不包括下标所在数字),因为下标所在数字是其正确的位置。
⑥前后两部分分别进行②③循环,形成递归(并且递归的时候,每次至少将一个数字移动到其正确的位置)。直到每部分剩了一个数字为止(剩2个数字的时候依然在交换,并且交换后两部分各一个数字然后停止)。
代码:
int n = 100;int m[100];for (int i = 0; i < n; i++)//赋值,从m[0]到m[99],值是100->1m[i] = 100 - i;for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";cout << "————分割线————" << endl;QuickSort(m, 0, 99);for (int i = 0; i < n; i++) //显示当前排序cout << m[i] << " ";void swap(int&a, int&b) //交换2个值
{int temp = a;a = b;b = temp;
}void QuickSort(int*m, int f, int l) //参数为数组、第一个下标和最后一个下标
{int mid;if (f < l) //如果第一个比最后一个小{mid = getMid(m, f, l); //得到中间值,并将中间值放到最中间位置QuickSort(m, f, mid - 1); //从开始到中间前一个QuickSort(m, mid + 1, l); //从中间后一个到最后}
}int getMid(int*m, int f, int l) //参数为,数组,第一个下标,最后一个下标
{int key = m[f]; //key是第一个数字的下标while (f < l){while (f < l&&m[l] >= key) //第一个下标比最后一个下标小,并且最后一个下标的值大于等于key(第一个下标的值)l--; //最后一个往里面靠一位,直到找到一个后面比前面小标小的swap(m[f], m[l]); //因为后面比前面那个小,所以交换之while (f < l&&m[f] <= key) //最前面那个下标比key小,则最前面的下标往后移动一位f++;swap(m[f], m[l]); //这是前面的m[f]比后面的大了,所以交换}return f; //返回该数字的下标(由于前后重合了,所以f=l
}
从零开始_学_数据结构(六)——排序(冒泡、插入、希尔、简单选择、归并、快速)...相关推荐
- 排序入门的七种算法(冒泡—插入—希尔—堆—选择—归并—快速)
---------文中的部分代码思路参考自<大话数据结构>一书. 目录 冒泡排序 插入排序 希尔排序 堆排序 选择排序 归并排序 快速排序 冒泡排序 原始的冒泡排序是对整个序列相邻两数字间 ...
- 【排序算法】图解简单选择排序(图解堪比Debug显示每次循环结果)
[排序算法]图解简单选择排序(图解堪比Debug分析每次循环结果) 写在前面: 本文主要介绍简单选择排序算法,通过图片一步步解释每一趟每一次的后移.代码通过C#实现,并输出每一次交换的情况和比较次数, ...
- 选择排序java代码_JAVA简单选择排序算法原理及实现
简单选择排序:(选出最小值,放在第一位,然后第一位向后推移,如此循环)第一位与后面每一个逐个比较,每次都使最小的置顶,第一位向后推进(即刚选定的第一位是最小值,不再参与比较,比较次数减1) 复杂度: ...
- 【简单排序算法】:简单选择排序、直接插入排序和冒泡排序
[简单排序算法]:简单选择排序.直接插入排序和冒泡排序 简单选择排序: 原理:设所排序序列的记录个数为n.i取1,2,-,n-1,每次从所有n-i+1个记录(Ri,Ri+1,-,Rn)中找出最小的记录 ...
- 【数据结构-排序】3.图解选择排序两种实现(简单选择排序/堆排序)
简单选择排序(选择排序) 排序思想 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置 然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾. 以此类推,直到所有元素 ...
- 排序算法入门之简单选择排序
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在学了冒 ...
- C语言实现各个排序算法(直接插入排序,折半插入排序,希尔排序,冒泡排序,简单选择排序)
数据结构开发总结报告 --内部排序综合设计程序的编程实现 #include<stdio.h> #define MaxSize 20 #include<windows.h> ty ...
- 从零开始_学_数据结构(二)——树的基本概念
相比之前的帖子,对其进行了增添和完善. ps:本颜色的字体是后续添加内容 ------------------ 参考链接: 大话数据结构.pdf 图解数据结构(6)--树及树的遍历 http://ww ...
- 从零开始_学_数据结构(五)——STL(map、set、list、vector)
STL容器 前注: STL(标准模板库)是一个C++的软件库,也是C++标准程序库的一部分. 这些容器,应该都是STL里面的一个类. vector封装数组.list封装链表.map和set封装二叉树 ...
最新文章
- 华人博士生首次尝试用两个Transformer构建一个GAN
- 设计模式--工厂方法(Factory Method)模式
- 如何获得春季周? for investment banking
- 记 QT 应用开发中的一个二进制兼容性问题
- 一篇来自前端同学对后端接口的吐槽
- Linux 命令之 lsusb -- 显示本机的USB设备列表信息
- 仓鼠大厦java下载_仓鼠大厦食盐宫殿 世界古怪酒店TOP10(组图)
- 蔚来:首台ET7白车身合肥工厂下线
- java.io.IOException: Bad connect ack with firstBad
- Bootstrap3的简单入门
- 【2019南京网络赛:F】Greedy Sequence(set/线段树 + 思维)
- 天堂2地点坐标(SQL语句,可直接导入数据库)
- web前端程序员前景及优劣势分析
- HackTheBox-Chaos-CTF_解题过程
- 高博课程编程作业之计算小萝卜的坐标
- 屏的接口类型种类以及接口定义分析
- c语言以字符输出88,C语言88案例完整版
- ntoskrnl导致的蓝屏死机问题
- 正确的java语句,下面哪条Java语句可以正确输出“HelloJava!”?()
- linux下emmc检测工具,eMMC check(eMMC芯片是否新机检测工具)1.3.0 安卓版
热门文章
- 建筑工程的发展、未来那个职业将会兴起!
- 数据挖掘导论读书笔记5关联分析的基本概念和算法
- Linux 安装iostat命令
- 38.6. Web IRC
- linux中LVM动态扩容和管理
- 文件翻译002片:Process Monitor帮助文档(Part 2)
- 随笔-20150513
- WindowsAPI开发常用资料
- (转载) 数组a[]={3,5,2,4,1,8},要求从a中找出所有“和”等于10的子集
- 【原创】parseInt大改造