数据结构--排序总结
2017-12-04 11:51
267 查看
二、插入排序
(一) 思想:在一个已经排好序的序列中,将未被排进的元素按照原先的规定插入到指定位置
1、直接插入排序
直接插入排序基本要求:假设待排序的记录存放在数组r[0…n-1].开始时,先将r[0]组成一个有序子表,然后依次将后面的记录插入到这个子表中,并一直保持子表的有序性。
1.1 直接插入排序的主要步骤:
(1)将r[i]暂存在临时变量temp中
(2)将temp与rj依次比较,若r[j].key>temp.key,则将r[j]后移一个位置,直到temp.key>=r[j].key为止,
(3)将temp插入到j+1的位置上
(4)令i=1,2,3,..,n-1,重复以上步骤1-3
1.2
(1)时间复杂度:T(n) = O(n²)。
(2)空间复杂度:S(n) = O(1)。
(3)稳定性:稳定排序。循环条件while(r[0].key < r[j].key)保证的。
(4)程序:
2、折半查找法
(1)思想:类比于直接插入法,在进行插入的时候不同于直接插入法对已排好序的元素依次比较,而是进行折半比较,减少比较次数。
(2)时间复杂度:比较时的时间减为O(n㏒n),但是移动元素的时间耗费未变,所以总是得时间复杂度还是O(n²)。、
(3)空间复杂度:S(n) = O(1)。
(4)稳定性:稳定排序。
(5)程序:
3、希尔排序
① 思想:又称缩小增量排序法。把待排序序列分成若干较小的子序列,然后逐个使用直接插入排序法排序,最后再对一个较为有序的序列进行一次排序,主要是为了减少移动的次数,提高效率。原理应该就是从无序到渐渐有序,要比直接从无序到有序移动的次数会少一些。
② 时间复杂度:O(n的1.5次方)
③ 空间复杂度:O(1)
④ 稳定性:不稳定排序。{2,4,1,2},2和1一组4和2一组,进行希尔排序,第一个2和最后一个2会发生位置上的变化。
⑤ 程序:
三、交换排序
(1)思想
两两待排序记录的关键字,若两个记录的次序相反则交换这两个记录,直到没有反序的记录为止,交换排序的主要方法有:冒泡排序和快速排序
1、 冒泡排序:
① 思想:反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。第一趟,从第一个数据开始,比较相邻的两个数据,(以升序为例)如果大就交换,得到一个最大数据在末尾;然后进行第二趟,只扫描前n-1个元素,得到次大的放在倒数第二位。以此类推,最后得到升序序列。如果在扫描过程中,发现没有交换,说明已经排好序列,直接终止扫描。所以最多进行n-1趟扫描。
② 时间复杂度:T(n) = O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。
⑤ 程序:
2、快速排序
2、 快速排序:
① 思想:冒泡排序一次只能消除一个逆序,为了能一次消除多个逆序,采用快速排序。以一个关键字为轴,从左从右依次与其进行对比,然后交换,第一趟结束后,可以把序列分为两个子序列,然后再分段进行快速排序,达到高效。
② 时间复杂度:平均T(n) = O(n㏒n),最坏O(n²)。
③ 空间复杂度:S(n) = O(㏒n)。
④ 稳定性:不稳定排序。{3, 2, 2}
⑤ 程序:
四、选择类排序:
(一) 思想:每一趟在n – i + 1 ( i = 1,2, … , n - 1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。
(二) 分类:
1、 简单选择排序:
① 思想:第一趟时,从第一个记录开始,通过n – 1次关键字的比较,从n个记录中选出关键字最小的记录,并和第一个记录进行交换。第二趟从第二个记录开始,选择最小的和第二个记录交换。以此类推,直至全部排序完毕。
② 时间复杂度:T(n) = O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序,{3, 3, 2}。
⑤ 程序:
2、 树形选择排序:
① 思想:为了减少比较次数,两两进行比较,得出的较小的值再两两比较,直至得出最小的输出,然后在原来位置上置为∞,再进行比较。直至所有都输出。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:较简单选择排序,增加了n-1个额外的存储空间存放中间比较结果,就是树形结构的所有根节点。S(n) = O(n)。
④ 稳定性:稳定排序。
⑤ 程序:
3、 堆排序:
① 思想:把待排序记录的关键字存放在数组r[1…n]中,将r看成是一刻完全二叉树的顺序表示,每个节点表示一个记录,第一个记录r[1]作为二叉树的根,一下个记录r[2…n]依次逐层从左到右顺序排列,任意节点r[i]的左孩子是r[2i],右孩子是r[2i+1],双亲是r[i/2向下取整]。然后对这棵完全二叉树进行调整建堆。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序。{5, 5, 3}
⑤ 程序:
(1) 筛选法调整堆:
由堆的定义可知,堆顶结点的左右子树也是堆,当将堆顶最小关键字值得节点与堆最后一个节点(第n-1个节点)交换后,这个根节点与其左右子树之间的可能不符合堆得定义,此时需要调整根节点与其左右两个堆顶节点之间的大小关系,使之符合定义。
调整方法:将根节点与左右孩子中较小的节点进行交换,继续对交换的子树进行相同的操作。直到叶子节点或堆被建成为止,这种从堆顶到叶子结点的调整过程也称为“筛选”
(2)堆排序算法
五、归并排序:
(一) 思想:
(二) 分类:
1、 归并排序:
① 思想:假设初始序列有n个记录,首先将这n个记录看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2向上取整 个长度为2(n为奇数时,最后一个序列的长度为1)的有序子序列。在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的有序子序列。如此重复,直至得到一个长度为n的有序序列为止。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:S(n) = O(n)。
④ 稳定性:稳定排序。
⑤ 程序:
(一) 思想:在一个已经排好序的序列中,将未被排进的元素按照原先的规定插入到指定位置
1、直接插入排序
直接插入排序基本要求:假设待排序的记录存放在数组r[0…n-1].开始时,先将r[0]组成一个有序子表,然后依次将后面的记录插入到这个子表中,并一直保持子表的有序性。
1.1 直接插入排序的主要步骤:
(1)将r[i]暂存在临时变量temp中
(2)将temp与rj依次比较,若r[j].key>temp.key,则将r[j]后移一个位置,直到temp.key>=r[j].key为止,
(3)将temp插入到j+1的位置上
(4)令i=1,2,3,..,n-1,重复以上步骤1-3
1.2
(1)时间复杂度:T(n) = O(n²)。
(2)空间复杂度:S(n) = O(1)。
(3)稳定性:稳定排序。循环条件while(r[0].key < r[j].key)保证的。
(4)程序:
public void insertSort(RecordType r[], int length) { for (i=2;i<=length;i++) { r[0]=r[i];//将r[0]设为监视哨 for(j=i-1;r[0].key<r[j].key;j--)//r[0]==r[0]即为j的终止条件 { r[j+1]=r[j]; } r[j+1]=r[0]; } }
2、折半查找法
(1)思想:类比于直接插入法,在进行插入的时候不同于直接插入法对已排好序的元素依次比较,而是进行折半比较,减少比较次数。
(2)时间复杂度:比较时的时间减为O(n㏒n),但是移动元素的时间耗费未变,所以总是得时间复杂度还是O(n²)。、
(3)空间复杂度:S(n) = O(1)。
(4)稳定性:稳定排序。
(5)程序:
void BinSort(RecordType r[], int length) { for(i=2;i<=length;i--)//i为待插入元素的位置 { r[0]=r[i]//将r[0]设为监视哨 low=1; high=i-1; while(low<=high)//通过while找到要插入的位置为low { mid=(low+high)/2; if (r[0].key<r[mid].key) high=mid-1; else low=mid+1; }//最终low的位置就是要插入数值的位置 for(j=i-1;j>=low;j--) { r[j+1]=r[j]; } r[low]=r[0]; }
3、希尔排序
① 思想:又称缩小增量排序法。把待排序序列分成若干较小的子序列,然后逐个使用直接插入排序法排序,最后再对一个较为有序的序列进行一次排序,主要是为了减少移动的次数,提高效率。原理应该就是从无序到渐渐有序,要比直接从无序到有序移动的次数会少一些。
② 时间复杂度:O(n的1.5次方)
③ 空间复杂度:O(1)
④ 稳定性:不稳定排序。{2,4,1,2},2和1一组4和2一组,进行希尔排序,第一个2和最后一个2会发生位置上的变化。
⑤ 程序:
public void shellSort(int[] d){//d[]为增量数组 RecordNode temp; int i,j; //对增量数组中的每个值进行扫描 for (int bcd0 k=0;k<=d.length;k++){ //一趟中若干子表,每个记录在自己所属的子表内进行直接插入排序 int dk=d[k]; //r待排序的数组中前dk个元素分别属于dk增量下的dk个子表中的首元素 for(i=dk;i<this.curlen;i++){ temp=r[i]; for(j=i-dk;j>=0&&temp.key<r[j].key;j-=dk){ r[j+dk]=r[j]; } r[j+dk]=temp; } } }
三、交换排序
(1)思想
两两待排序记录的关键字,若两个记录的次序相反则交换这两个记录,直到没有反序的记录为止,交换排序的主要方法有:冒泡排序和快速排序
1、 冒泡排序:
① 思想:反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。第一趟,从第一个数据开始,比较相邻的两个数据,(以升序为例)如果大就交换,得到一个最大数据在末尾;然后进行第二趟,只扫描前n-1个元素,得到次大的放在倒数第二位。以此类推,最后得到升序序列。如果在扫描过程中,发现没有交换,说明已经排好序列,直接终止扫描。所以最多进行n-1趟扫描。
② 时间复杂度:T(n) = O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。
⑤ 程序:
public void bublleSort() { RecordNode temp;//辅助节点 boolean flag=true;//是否交换标志 for(i=1;i<this.curlen&&flag;i++) { flag=false;//记录未交换 for(j=0;j<this.curlen-i;j++) { if(r[j]>r[j+1]) { temp=r[j+1]; r[j+1]=r[j]; r[j]=temp; flag=true; } } } }
2、快速排序
2、 快速排序:
① 思想:冒泡排序一次只能消除一个逆序,为了能一次消除多个逆序,采用快速排序。以一个关键字为轴,从左从右依次与其进行对比,然后交换,第一趟结束后,可以把序列分为两个子序列,然后再分段进行快速排序,达到高效。
② 时间复杂度:平均T(n) = O(n㏒n),最坏O(n²)。
③ 空间复杂度:S(n) = O(㏒n)。
④ 稳定性:不稳定排序。{3, 2, 2}
⑤ 程序:
void QKSort(RecordType r[],int i, int j) { int pos; if(i<j){ pos=QKPass(r,i,j); QKSort(r,i,pos-1); QKSort(r,pos+1,j); } } int QKPass(RecordType r[],int i, int j) { RecordNode pivot=r[i]; while(i<j){ while(i<j&&pivot<=r[j]){ j--; } if(i<j){ r[i]=r[j]; i++; } while(i<j&&pivot>r[i]){ i++; } if(i<j){ r[j]=r[i]; j--; } } r[i]=pivot; return i; }
四、选择类排序:
(一) 思想:每一趟在n – i + 1 ( i = 1,2, … , n - 1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。
(二) 分类:
1、 简单选择排序:
① 思想:第一趟时,从第一个记录开始,通过n – 1次关键字的比较,从n个记录中选出关键字最小的记录,并和第一个记录进行交换。第二趟从第二个记录开始,选择最小的和第二个记录交换。以此类推,直至全部排序完毕。
② 时间复杂度:T(n) = O(n²)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序,{3, 3, 2}。
⑤ 程序:
public void selectSort(){ RecordNode temp; for(int i=0;i<this.curlen;i++){//n-1趟排序 //每趟从r[i]开始的子序列中寻找最小关键字值得记录 int min=i; for(int j=i+1;j<this.curlen;j++){ //在子序列中寻找关键字最小的记录 if(r[j]<r[min]) min=j; } if(min!=i){ temp=r[i]; r[i]=r[min]; r[min]=temp; } } }
2、 树形选择排序:
① 思想:为了减少比较次数,两两进行比较,得出的较小的值再两两比较,直至得出最小的输出,然后在原来位置上置为∞,再进行比较。直至所有都输出。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:较简单选择排序,增加了n-1个额外的存储空间存放中间比较结果,就是树形结构的所有根节点。S(n) = O(n)。
④ 稳定性:稳定排序。
⑤ 程序:
3、 堆排序:
① 思想:把待排序记录的关键字存放在数组r[1…n]中,将r看成是一刻完全二叉树的顺序表示,每个节点表示一个记录,第一个记录r[1]作为二叉树的根,一下个记录r[2…n]依次逐层从左到右顺序排列,任意节点r[i]的左孩子是r[2i],右孩子是r[2i+1],双亲是r[i/2向下取整]。然后对这棵完全二叉树进行调整建堆。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序。{5, 5, 3}
⑤ 程序:
(1) 筛选法调整堆:
由堆的定义可知,堆顶结点的左右子树也是堆,当将堆顶最小关键字值得节点与堆最后一个节点(第n-1个节点)交换后,这个根节点与其左右子树之间的可能不符合堆得定义,此时需要调整根节点与其左右两个堆顶节点之间的大小关系,使之符合定义。
调整方法:将根节点与左右孩子中较小的节点进行交换,继续对交换的子树进行相同的操作。直到叶子节点或堆被建成为止,这种从堆顶到叶子结点的调整过程也称为“筛选”
//将以low为根节点的字数调整成小顶堆,low和high分别是序列的下界和上界 public void sift(int low, int high){ int i=low; //子树为根节点 int j=2*i;//j为i的左孩子 RecordNode temp=r[i]; while(j<high){ if(j<high-1&&r[j]>r[j+1]) j++;//记录比较,j为左右孩子的较小者 if(temp.key>r[j]){//若父节点较大 r[j]=r[i];//孩子节点中较小者上移 i=j; j=2*j+1; }else{ j=high+1; } } r[i]=temp; }
(2)堆排序算法
public void heapSort(){ System.out.println("堆排序"); int n=this.curlen; RecordNode temp; //创建堆,即从第一个非叶子节点开始自下而上调整堆; for(int i=n/2-1;i>=0;i--){ sift(i,n); } for(int i=n-1;i>0;i--){ //每趟将最小关键字交换到后面,在调整成堆 temp=r[0]; r[0]=r[i]; r[i]=temp; sift(0,i); } }
五、归并排序:
(一) 思想:
(二) 分类:
1、 归并排序:
① 思想:假设初始序列有n个记录,首先将这n个记录看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2向上取整 个长度为2(n为奇数时,最后一个序列的长度为1)的有序子序列。在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的有序子序列。如此重复,直至得到一个长度为n的有序序列为止。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:S(n) = O(n)。
④ 稳定性:稳定排序。
⑤ 程序:
//两个有序序列归并算法把r数组中两个相邻的有序表r[h]-r[m]和r[m+1]-、r[t]归并为一个有序表order[h]-order[t] public void merge(RecordNode[] r,RecordNode[] order, int h, int m, int t){ int i=h,j=m+1,k=h; while(i<=m&&j<=t){ //将r中的两个相邻子序列归并到ORDER中 if(r[i].key<r[j].key){//将较小者复制到order中 order[k++]=r[i++]; }else{ order[k++]=r[j++]; } while(i<=m){//将前一个子序列剩余元素复制到order中 order[k++]=r[i++]; } while(j<=t){ order[k++]=r[j++];//将后一个子序列剩余元素复制到order中 } } }
//一趟归并排序 public void mergepass(RecordNode[] r,RecordNode[] order,int s,int n){ int p=0; //P为每一位待合并表的第1个元素的下标,初值为0 while(p+2*s-1<=n-1){//两两归并长度为s的有序表 merge(r,order,p,p+s-1,p+2*s-1); p=2*s; } if(p+s-1<n-1)//n-1为最后一位元素,说明此事还有两个有序表{ merge(r,order,p,p+s-1,n-1); }else{ for(int i=p;i<=n-1;i++){ order[i]=r[i]; } } }
//二路归并排序算法 public void mergeSort(){ System.out.println("归并排序"); int s=1; int n=this.curlen; RecordNode[] temp=new RecordNode ;//定义长度为n的辅助数组temp while(s<n){ mergepass(r,temp,s,n);//一趟归并,将r数组中各子序列归并到temp中 display(); s*=2; mergepass(temp,r,s,n);//将temp数组中各子序列归并到r中 display(); s*=2; } }
相关文章推荐
- 数据结构几类排序的总结和完整代码 待续。。
- 数据结构-排序总结(冒泡 插入 选择 归并)
- 数据结构面试之十二——排序3(排序算法归类、排序时间、空间复杂度、稳定性总结)
- 数据结构 JAVA描述(十三) 排序总结
- 数据结构-链表排序总结
- 关于数据结构三种简单的排序总结
- 数据结构复习 快速排序个人总结
- 数据结构中的各种排序---总结篇
- [置顶] 数据结构知识点总结--排序
- 各种排序(数据结构复习之内部排序算法总结)
- 数据结构和算法总结(二):排序
- 数据结构学习系类列十六-排序总结篇
- 数据结构排序之总结2
- 数据结构(二)排序总结
- 数据结构 排序 总结
- 数据结构中的各种排序---总结篇
- 数据结构第十章 排序 总结
- 数据结构中的各种排序总结
- 关于数据结构中冒泡排序和选择排序的总结
- 数据结构之排序:排序基本概念和各种排序方法总结