8种排序之折半插入排序
C语言数组的五种简单排序,选择法排序,冒泡法排序、交换法排序、插入法排序、折半法排序
C语⾔数组的五种简单排序,选择法排序,冒泡法排序、交换法排序、插⼊法排序、折半法排序⽂章⽬录1、选择法排序选择法排序是指每次选择索要排序的数组中的最⼩值(这⾥是由⼩到⼤排序,如果是由⼤到⼩排序则需要选择最⼤值)的数组元素,将这些数组元素的值与前⾯没有进⾏排序的数组元素值进⾏互换代码实现需要注意的是:声明⼀个数组和两个整形变量,数组⽤于存储输⼊的数字,⽽整形变量⽤于存储最⼩的数组元素的数值与该元素的位置,在我的代码中实现为a[] temp position。
代码具体如下#include<stdio.h>int main(){int m,n,k;printf("please input the length of the array:");scanf("%d",&k);int a[k];int temp;int position;printf("please input the number of the array:\n");for(m=0;m<k;m++){printf("a[%d]=",m+1);scanf("%d",&a[m]);}/*从⼩到⼤排序*/for(m=0;m<k-1;m++){temp=a[m]; //设置当前的值为最⼩值position=m; //记录当前的位置for(n=m+1;n<k;n++){if(a[n]<temp){temp=a[n]; //如果找到⽐当前的还要⼩的数值,则更换最⼩的数值与位置position=n;}}a[position]=a[m];a[m]=temp;}for(m=0;m<k;m++){printf("%d\t",a[m]);}return 0;}结果如下2、冒泡法排序冒泡法排序就是值在排序时,每次⽐较数组中相邻的两个数组元素的值,将⽐较⼩的(从⼩到⼤排序算法,如果是从⼤到⼩排序算法就是将较⼤的数排在较⼩的数前⾯)排在⽐较⼤的前⾯在代码实现的过程中:声明⼀个数组与⼀个整型变量,数组⽤于存放数据元素,整型变量⽤于交换时作为中间变量。
排序大全
(共八种排序方法:直接插入排序,折半插入排序,冒泡排序,简单选择排序,希尔排序,快速排序,堆排序,归并排序)一.简单排序1.直接插入排序:a)思想:每次从后面无序表中取出第一个元素,通过循环比较把它插入到前面有序表的合适位置,使前面有序表仍然有序。
b)稳定性:稳定c)时空效率:时间复杂度:O(n^2) 空间复杂度:O(1)d)代码:/******************************************function: InsertSort 直接插入排序paramaters: list[] 形参数组length 数组长度(并非最大下标)******************************************/void InsertSort(int list[],int length){int temp,i,j;for(i=1;i<length;i++){if(list[i]<list[i-1]){temp=list[i];//保存小值list[i]=list[i-1];//大值向后移一位for(j=i-1;j>=1&&temp<list[j-1];j--){list[j]=list[j-1];}list[j]=temp;}}}2.折半插入排序:a) 思想:在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,如果小,则对前半再进行折半,否则对后半进行折半,直到low>hight,找到插入位置low,然后把low到i-1的所有元素均后移一位,再把第i个元素放在目标位置low上。
b) 稳定性:稳定c) 时空效率:时间复杂度:O(n^2) 空间复杂度:O(1)d) 代码:/******************************************function: BInsertSort 折半插入排序又叫二分法插入排序paramaters: list[] 形参数组length 数组长度(并非最大下标)******************************************/void BInsertSort(int p[],int length){int i,j,low,high,m,temp;for(i=1;i<length;i++){temp=p[i];low=0;high=i-1;while(low<=high){m=(low+high)/2;if(p[i]<p[m])//插入点是high+1,而非m,因为有的循环m变化了,而m与high没有发生关系,//循环就结束了,他们的关系还保留在上一层,因此插入点应该用high来保存{high=m-1;}else low=m+1;}// 其实用low更方便点,不用再对low做任何改变/*for(j=i-1;j>=high+1;j--){p[j+1]=p[j];}p[high+1]=temp;*/for(j=i-1;j>=low;j--){p[j+1]=p[j];}p[low]=temp;}}3.冒泡排序:a) 思想:依次比较相邻的两个数,将小数放在前面,大数放在后面。
(19)第八章 排序
21 21
i=2
0 25
1 21 21
2 25 25 25 25 25
3 49 49 49 49 49
4 5 25* 16 25* 16 25* 16 25* 16 25* 16
6 08 08 08 08 08
i=3
49
21 21
i=4
25*
21
21
25
25*
49
16
08
9
i=3
49
21 21
25 25 25 25 25
排序的时间开销: 排序的时间开销是衡量算法好 坏的最重要的标志。排序的时间开 销主要取决于算法执行中的数据比 较次数与数据移动次数。
4
内部排序分类
依排序的实现方法进行分类 插入排序、交换排序、选择排序、 归并排序、和基数排序等。 依算法的执行效率进行分类 简单排序---时间复杂度O(n2) 先进排序方法---时间复杂度O(n log2n)
25* 16 49 16
08
08 08
7
i=4
25*
21 21
i=2
0 25
1 21
21
2 25
25 25
3 49
49 49
4 5 25* 16
25* 16 25* 16
6 08
08 08
i=3
49
21
21
25
25 25
49
49 25*
25* 16
25* 16 49 16
08
08 08
8
i=4
25*
15
折半插入排序的算法 注意,最后折半结束
后有: higt+1=low void BinInsSort ( SqList &L ) { int low, high; for ( int i = 2; i < =L.length; i++) { //L.r[0]空闲无用 low = 1; high = i-1; L.r[0].key = L.r[i].key; while ( low <= high ) { //折半查找插入位置 int mid = ( low + high )/2; if ( L.r[0].key < L.r[mid].key ) high = mid - 1; else low = mid + 1; } for ( int j = i-1; j >= high+1; j-- ) L.r[j+1]= L.r[j]; //记录后移 L.r[high+1] = L.r[0]; //插入
源代码--数据结构与算法(Python版)chap10 排序
交换类
(2)快速排序 快速排序采用分而治之(Divide and Conquer)
的策略将问题分解成若干个较小的子问题,采用 相同的方法一一解决后,再将子问题的结果整合 成最终答案。快速排序的每一轮处理其实就是将 这一的基准数定位,直到所有的数都排序完成 为止。
21
快速排序的基本步骤:
1. 选定一个基准值(通常可选第一个元素); 2. 将比基准值小的数值移到基准值左边,形
14
• 交换类
交换类排序的基本思想是:通过交换无序序列 中的记录得到其中关键字最小或最大的记录,并将 其加入到有序子序列中,最终形成有序序列。交换 类排序可分为冒泡排序和快速排序等。
15
交换类
(1)冒泡排序 两两比较待排序记录的关键字,发现两
个记录的次序相反时即进行交换,直到没有 反序的记录为止。因为元素会经由交换慢慢 浮到序列顶端,故称之为冒泡排序。
3. 最后对这个组进行插入排序。步长的选法 一般为 d1 约为 n/2,d2 为 d1 /2, d3 为 d2/2 ,…, di = 1。
11
【例】给定序列(11,9,84,32,92,26,58,91,35, 27,46,28,75,29,37,12 ),步长设为d1 =5、d2 =3、 d3 =1,希尔排序过程如下:
for i in range(1,len(alist)):
#外循环n-1
for j in range(i,0,-1):
#内循环
if alist[j]<alist[j-1]:
alist[j],alist[j-1]=alist[j-1],alist[j] #交换
li=[59,12,77,64,72,69,46,89,31,9] print('before: ',li) insert_sort(li) print('after: ',li)
数据结构第八章_排序
49 38 65 97 76
三趟排序:4 13 27 38 48 49 55 65 76 97
算法描述
#define T 3 int d[]={5,3,1};
例 13 48 97 55 76 4 13 49 27 38 65 49 27 38 65 48 97 55 76 4 j j j
j
j
i
例 初始: 49 38 65 97 76 13 27 48 55 4 取d1=5 49 38 65 97 76 13 27 48 55 4 一趟分组:
一趟排序:13 27 48 55 4 取d2=3 13 27 48 55 4 二趟分组:
49 38 65 97 76 49 38 65 97 76
二趟排序:13 4 48 38 27 49 55 65 97 76 取d3=1 13 27 48 55 4 三趟分组:
初始时令i=s,j=t
首先从j所指位置向前搜索第一个关键字小于x的记录,并和rp
交换 再从i所指位置起向后搜索,找到第一个关键字大于x的记录, 和rp交换 重复上述两步,直至i==j为止 再分别对两个子序列进行快速排序,直到每个子序列只含有 一个记录为止
快速排序演示
算法描述
算法评价
例
38 49 49 38 65 76 97 13 97 76 97 27 13 30 97 27 97 30 初 始 关 键 字
38 49 65 13 76 27 76 13 30 76 27 76 30 97 第 一 趟
38 49 13 65 27 65 13 30 65 27 65 30
38 13 49
时间复杂度
最好情况(每次总是选到中间值作枢轴)T(n)=O(nlog2n) 最坏情况(每次总是选到最小或最大元素作枢轴)
使用C语言实现12种排序方法
使⽤C语⾔实现12种排序⽅法⽬录1.冒泡排序2.插⼊排序3.折半插⼊排序4.希尔排序5.选择排序6.鸡尾酒排序7.堆排序8.快速排序9.归并排序10.计数排序11.桶排序12.基数排序1.冒泡排序思路:⽐较相邻的两个数字,如果前⼀个数字⼤,那么就交换两个数字,直到有序。
时间复杂度O(n^2),稳定性:这是⼀种稳定的算法。
代码实现:void bubble_sort(int arr[],size_t len){size_t i,j;for(i=0;i<len;i++){bool hasSwap = false; //优化,判断数组是否已经有序,如果有序可以提前退出循环for(j=1;j<len-i;j++){ //这⾥j<len-i是因为最后⾯的肯定都是最⼤的,不需要多进⾏⽐较if(arr[j-1]>arr[j]){ //如果前⼀个⽐后⼀个⼤swap(&arr[j-1],&arr[j]); //交换两个数据hasSwap = true;}}if(!hasSwap){break;}}}2.插⼊排序思路:把⼀个数字插⼊⼀个有序的序列中,使之仍然保持有序,如对于需要我们进⾏排序的数组,我们可以使它的前i个数字有序,然后再插⼊i+1个数字,插⼊到合适的位置使之仍然保持有序,直到所有的数字有序。
时间复杂度:O(n^2) 稳定性:稳定的算法代码实现:void insert_sort(int arr[],int len){int i,j;for(i=1;i<len;i++){int key = arr[i]; //记录当前需要插⼊的数据for(j= i-1;i>=0&&arr[j]>key;j--){ //找到插⼊的位置arr[j+1] = arr[j]; //把需要插⼊的元素后⾯的元素往后移}arr[j+1] = key; //插⼊该元素}}3.折半插⼊排序思路:本质上是插⼊排序,但是通过半分查找法找到插⼊的位置,让效率稍微快⼀点。
查找和排序(折半查找、二叉插入查找、直接插入排序、折半排序、快速排序、选择排序、堆排序、归并排序)
int key;
cin>>key;
cout<<"折半查找:"<<endl;
Search_Bin(st,key);
cout<<"二叉排序查找"<<endl;
BiTree T=NULL;
for(i=0;i<st.length;i++)
SearchandIn(T,st.elem[i]);
{
MSort(L,L,1,L.length-1);
{
for(int i=1;i<L.length;i++)
cout<<L.r[i].key<<" ";
cout<<endl;
}
void main()
{
SSTable st;
--high;
int temp=L.r[low].key;
L.r[low].key=L.r[high].key;
L.r[high].key=temp;
while(low<high&&L.r[low].key<=pivotkey)
++low;
temp=L.r[low].key;
return false;
}
if(key==T->data)
return true;
else if(key<T->data)
return SearchandIn(T->lchild,key);
排序算法:折半插入排序
排序算法:折半插⼊排序算法分析:(1)时间复杂度 从时间上⽐较,折半查找⽐顺序查找快,所以就平均性能来说,折半插⼊排序优于直接插⼊排序。
折半插⼊排序所需要的关键字⽐较次数与待排序序列的初始排列⽆关,仅依赖于记录的个数。
不论初始序列情况如何,在插⼊第i个记录时,需要经过logi+1(向下取整+1)次⽐较,才能确定它插⼊的位置。
所以当记录的初始排列为正序或接近正序时,直接插⼊排序⽐折半插⼊排序执⾏的关键字⽐较次数要少。
折半插⼊排序的对象移动次数与直接插⼊排序相同,依赖于对象的初始排列。
在平均情况下,折半插⼊排序仅减少了关键字的⽐较次数,⽽记录的移动次数不变。
因此,折半插⼊排序的时间复杂度仍然为O(n^2)。
(2)空间复杂度 折半插⼊排序所需附加存储空间和直接插⼊排序相同,只需要⼀个记录的辅助空间r[0],所以空间复杂度为O(1)算法特点:(1)是稳定排序。
(2)因为要进⾏折半插⼊查找,所以只能⽤于顺序结构,不能⽤于链式结构。
(3)适合初始记录⽆序、n较⼤的情况。
#include<iostream>#include<vector>using namespace std;void BSort(int a[],int n){for (int i = 1; i < n; i++)//数组中的第⼀个元素最为已经排好的序列,所以从数组的第⼆个元素开始排{int key = a[i];//带插⼊元素int low = 0, high = i - 1;while (low <= high){int mid = (low + high) / 2;if (key < a[mid]){high = mid - 1;}else{low = mid + 1;}}for (int j = i - 1; j >= high + 1; j--){//i-1是已经排好序的序列的数量,high+1是待插⼊的的位置,元素后移腾出high+1这个位置a[j + 1] = a[j];}a[high + 1] = key;}}int main(){int a [11] = { 2,6,4,5,54,53,53,5,34,34,32};BSort(a, 11);for (int i = 0; i < 11; i++){cout << a[i] << " ";}return 0;}。
用Java实现常见的8种内部排序算法
⽤Java实现常见的8种内部排序算法⼀、插⼊类排序插⼊类排序就是在⼀个有序的序列中,插⼊⼀个新的关键字。
从⽽达到新的有序序列。
插⼊排序⼀般有直接插⼊排序、折半插⼊排序和希尔排序。
1. 插⼊排序1.1 直接插⼊排序/*** 直接⽐较,将⼤元素向后移来移动数组*/public static void InsertSort(int[] A) {for(int i = 1; i < A.length; i++) {int temp = A[i]; //temp ⽤于存储元素,防⽌后⾯移动数组被前⼀个元素覆盖int j;for(j = i; j > 0 && temp < A[j-1]; j--) { //如果 temp ⽐前⼀个元素⼩,则移动数组A[j] = A[j-1];}A[j] = temp; //如果 temp ⽐前⼀个元素⼤,遍历下⼀个元素}}/*** 这⾥是通过类似于冒泡交换的⽅式来找到插⼊元素的最佳位置。
⽽传统的是直接⽐较,移动数组元素并最后找到合适的位置*/public static void InsertSort2(int[] A) { //A[] 是给定的待排数组for(int i = 0; i < A.length - 1; i++) { //遍历数组for(int j = i + 1; j > 0; j--) { //在有序的序列中插⼊新的关键字if(A[j] < A[j-1]) { //这⾥直接使⽤交换来移动元素int temp = A[j];A[j] = A[j-1];A[j-1] = temp;}}}}/*** 时间复杂度:两个 for 循环 O(n^2)* 空间复杂度:占⽤⼀个数组⼤⼩,属于常量,所以是 O(1)*/1.2 折半插⼊排序/** 从直接插⼊排序的主要流程是:1.遍历数组确定新关键字 2.在有序序列中寻找插⼊关键字的位置* 考虑到数组线性表的特性,采⽤⼆分法可以快速寻找到插⼊关键字的位置,提⾼整体排序时间*/public static void BInsertSort(int[] A) {for(int i = 1; i < A.length; i++) {int temp = A[i];//⼆分法查找int low = 0;int high = i - 1;int mid;while(low <= high) {mid = (high + low)/2;if (A[mid] > temp) {high = mid - 1;} else {low = mid + 1;}}//向后移动插⼊关键字位置后的元素for(int j = i - 1; j >= high + 1; j--) {A[j + 1] = A[j];}//将元素插⼊到寻找到的位置A[high + 1] = temp;}}2. 希尔排序希尔排序⼜称缩⼩增量排序,其本质还是插⼊排序,只不过是将待排序列按某种规则分成⼏个⼦序列,然后如同前⾯的插⼊排序⼀般对这些⼦序列进⾏排序。
折半插入排序
折半插入排序
折半插入排序法,又称四舍五入排序法。
是按照折半法和插入法交替进行逐步排除错误的一种方法,也叫“舍弃小的,保留大的”或“用全排出去,用缺补上来”排序法.它适合于成对象形的数据,也就是说要求将某些对象先看作一组,然后再把它们每一对当作两个来排列,这样容易产生正确的结果。
常见的排序问题,通常包含多对对象,而且要求所选择的对象都必须有相同的特征值。
由于相邻的两个单元可能互为相反数,故在实际操作过程中往往需要将两者按互为倒数来处理,这就引申出一系列简便计算,即求整数部分的个位数字,因此排序也是很容易解决的。
下面举例说明其思路和方法。
例如有10名学生参加考试,前8人平均成绩为80分,最后2人平均成绩为90分,则求出平均成绩为81分的2人平均成绩的值。
应用该方法时要注意以下几点:1、运算符号、公式及各种运算之间不能混淆;2、在用这种方法时还需进一步分析原来顺序中有无矛盾,是否具备等价性(平均成绩相等),排除非同质的现象(比如全为80分,或全为90分);3、用该方法解决的问题,只要求得到最终结果,不要求知道开始时的情况,但要求知道结束时的情况。
在用这种方法时还需进一步分析原来顺序中有无矛盾,是否具备等价性(平均成绩相等),排除非同质的现象(比如全为80分,或全为90分)。
3、使用了这种方法后,若遇到不能直接利用上述方法解决的问
题,可采取折半插入排序法。
例如,已知某班男女生人数分别为20人和21人,求男生人数占总人数的百分比。
4、用该方法解决的问题,只要求得到最终结果,不要求知道开始时的情况,但要求知道结束时的情况。
Java实现二分(折半)插入排序
Java实现⼆分(折半)插⼊排序设有⼀个序列a[0],a[1]...a[n];当中a[i-1]前是已经有序的,当插⼊时a[i]时,利⽤⼆分法搜索a[i]插⼊的位置效率:O(N^2),对于初始基本有序的序列,效率上不如直接插⼊排序;对于随机⽆序的序列,效率⽐直接插⼊排序要⾼/** ⼆分(折半)插⼊排序* 设有⼀个序列a[0],a[1]...a[n];当中a[i-1]前是已经有序的,当插⼊时a[i]时,利⽤⼆分法搜索a[i]插⼊的位置*/public class BinaryInsertSort {public static void main(String[] args) {int len = 10;int[] ary = new int[len];Random random = new Random();for (int j = 0; j < len; j++) {ary[j] = random.nextInt(1000);}binaryInsert(ary);/** 复杂度分析:最佳情况,即都已经排好序,则⽆需右移,此时时间复杂度为:O(n lg n) 最差情况,所有逆序,此时复杂度为O(n^2) * ⽆法将最差情况的复杂度提升到O(n|logn)。
*/// 打印数组printArray(ary);}/*** 插⼊排序* @param ary*/private static void binaryInsert(int[] ary) {int setValueCount = 0;// 从数组第⼆个元素開始排序,由于第⼀个元素本⾝肯定是已经排好序的for (int j = 1; j < ary.length; j++) {// 复杂度 n// 保存当前值int key = ary[j];// Δ 利⽤⼆分查找定位插⼊位置// int index = binarySearchAsc(ary, ary[j], 0, j - 1);// 复杂度:O(logn)// int index = binarySearchDesc(ary, ary[j], 0, j - 1);// 复杂度:O(logn)int index = binarySearchDesc2(ary, ary[j], 0, j - 1);// 复杂度:O(logn)printArray(ary);System.out.println("第" + j +"个索引上的元素要插⼊的位置是:" + index);// 将⽬标插⼊位置,同⼀时候右移⽬标位置右边的元素for (int i = j; i > index; i--) {// 复杂度,最差情况:(n-1)+(n-2)+...+n/2=O(n^2)ary[i] = ary[i - 1]; //i-1 <==> indexsetValueCount++;}ary[index] = key;setValueCount++;}System.out.println("\n 设值次数(setValueCount)=====> " + setValueCount);}/*** ⼆分查找升序递归** @param ary* 给定已排序的待查数组* @param target* 查找⽬标* @param from* 当前查找的范围起点* @param to* 当前查找的返回终点* @return 返回⽬标在数组中,按顺序应在的位置*/private static int binarySearchAsc(int[] ary, int target, int from, int to) {int range = to - from;// 假设范围⼤于0,即存在两个以上的元素,则继续拆分if (range > 0) {// 选定中间位int mid = (to + from) / 2;// 假设临界位不满⾜,则继续⼆分查找if (ary[mid] > target) {/** mid > target, 升序规则,target较⼩,应交换位置前置,即target定位在mid位置上,* 依据查找思想,从from到 mid-1觉得有序,所以to=mid-1*/return binarySearchAsc(ary, target, from, mid - 1);} else {/** mid < target, 升序规则,target较⼤,不交换位置,查找⽐較的起始位置应为mid+1*/return binarySearchAsc(ary, target, mid + 1, to);}} else {if (ary[from] > target) {//如 5,4, 要插⼊的是4return from;} else {return from + 1;}}}/*** ⼆分查找降序,递归*/private static int binarySearchDesc(int[] ary, int target, int from, int to) {int range = to - from;if (range > 0) {int mid = (from + to) >>> 1;if (ary[mid] > target) {return binarySearchDesc(ary, target, mid + 1, to);} else {return binarySearchDesc(ary, target, from, mid - 1);}} else {if (ary[from] > target) {//如 5,4, 要插⼊的是4return from + 1;} else {return from;}}}/*** ⼆分查找降序,⾮递归*/private static int binarySearchDesc2(int[] ary, int target, int from, int to) {// while(from < to) {for (; from < to; ) {int mid = (from + to) >>> 1;if (ary[mid] > target) {from = mid + 1;} else {to = mid -1;}}//from <==> to;if (ary[from] > target) {//如 5,4, 要插⼊的是4return from + 1;} else {return from;}}private static void printArray(int[] ary) {for (int i : ary) {System.out.print(i + " ");}}}打印918 562 442 531 210 216 931 706 333 132 第1个索引上的元素要插⼊的位置是:1 918 562 442 531 210 216 931 706 333 132 第2个索引上的元素要插⼊的位置是:2 918 562 442 531 210 216 931 706 333 132 第3个索引上的元素要插⼊的位置是:2 918 562 531 442 210 216 931 706 333 132 第4个索引上的元素要插⼊的位置是:4 918 562 531 442 210 216 931 706 333 132 第5个索引上的元素要插⼊的位置是:4 918 562 531 442 216 210 931 706 333 132 第6个索引上的元素要插⼊的位置是:0 931 918 562 531 442 216 210 706 333 132 第7个索引上的元素要插⼊的位置是:2 931 918 706 562 531 442 216 210 333 132 第8个索引上的元素要插⼊的位置是:6 931 918 706 562 531 442 333 216 210 132 第9个索引上的元素要插⼊的位置是:9设值次数(setValueCount)=====> 24931 918 706 562 531 442 333 216 210 132。
插入排序——折半插入排序
插⼊排序——折半插⼊排序基本思想: 折半插⼊算法是对直接插⼊排序算法的改进,排序原理同直接插⼊算法: 把n个待排序的元素看成⼀个有序表和⼀个⽆序表,开始时有序表中只有⼀个元素,⽆序表中有n-1个元素;排序过程即每次从⽆序表中取出第⼀个元素,将它插⼊到有序表中,使之成为新的有序表,重复n-1次完成整个排序过程。
与直接插⼊算法的区别在于:在有序表中寻找待排序数据的正确位置时,使⽤了折半查找/⼆分查找。
实例: 与直接插⼊算法相区别的代码(⼆分查找):/*** 寻找temp插⼊有序列表的正确位置,使⽤⼆分查找法*/while(low <= high){/*** 有序数组的中间坐标,此时⽤于⼆分查找,减少查找次数*/int mid = (low+high)/2;/*** 若有序数组的中间元素⼤于待排序元素,则有序序列向中间元素之前搜索,否则向后搜索*/if(a[mid]>temp){high = mid-1;}else{low = mid+1;}}Java实现: package sort;/*** 折半插⼊排序的实现* 稳定算法* @author qimingwei**/public class InsertSort {public static void main(String[] args) {int a[] = {3,1,5,7,2,4,9,6};new InsertSort().binaryInsertSort(a);}/*** 折半插⼊排序算法的实现* @param a*/private void binaryInsertSort(int[] a) {System.out.println("———————————————————折半插⼊排序算法—————————————————————");int n = a.length;int i,j;for(i=1;i<n;i++){/*** temp为本次循环待插⼊有序列表中的数*/int temp = a[i];int low=0;int high=i-1;/*** 寻找temp插⼊有序列表的正确位置,使⽤⼆分查找法*/while(low <= high){/*** 有序数组的中间坐标,此时⽤于⼆分查找,减少查找次数*/int mid = (low+high)/2;/*** 若有序数组的中间元素⼤于待排序元素,则有序序列向中间元素之前搜索,否则向后搜索*/if(a[mid]>temp){high = mid-1;}else{low = mid+1;}}for(j=i-1;j>=low;j--){/*** 元素后移,为插⼊temp做准备 */a[j+1] = a[j];}/*** 插⼊temp*/a[low] = temp;/*** 打印每次循环的结果*/print(a,n,i);}/*** 打印排序结果*/printResult(a,n);}/*** 打印排序的最终结果* @param a* @param n*/private void printResult(int[] a, int n){System.out.print("最终排序结果:");for(int j=0;j<n;j++){System.out.print(" "+a[j]);}System.out.println();}/*** 打印排序的每次循环的结果* @param a* @param n* @param i*/private void print(int[] a, int n, int i) {System.out.print("第"+i+"次:");for(int j=0;j<n;j++){System.out.print(" "+a[j]);}System.out.println();}}。
排序算法总结
排序算法总结【篇一:排序算法总结】1、稳定排序和非稳定排序简单地说就是所有相等的数经过某种排序方法后,仍能保持它们在排序之前的相对次序,我们就说这种排序方法是稳定的。
反之,就是非稳定的。
比如:一组数排序前是a1,a2,a3,a4,a5,其中a2=a4,经过某种排序后为a1,a2,a4,a3,a5,则我们说这种排序是稳定的,因为a2排序前在a4的前面,排序后它还是在a4的前面。
假如变成a1,a4,a2,a3,a5就不是稳定的了。
2、内排序和外排序在排序过程中,所有需要排序的数都在内存,并在内存中调整它们的存储顺序,称为内排序;在排序过程中,只有部分数被调入内存,并借助内存调整数在外存中的存放顺序排序方法称为外排序。
3、算法的时间复杂度和空间复杂度所谓算法的时间复杂度,是指执行算法所需要的计算工作量。
一个算法的空间复杂度,一般是指执行这个算法所需要的内存空间。
功能:选择排序输入:数组名称(也就是数组首地址)、数组中元素个数算法思想简单描述:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。
选择排序是不稳定的。
【篇二:排序算法总结】在计算机科学所使用的排序算法通常被分类为:计算的复杂度(最差、平均、和最好性能),依据列表(list)的大小(n)。
一般而言,好的性能是O(nlogn),且坏的性能是O(n2)。
对于一个排序理想的性能是O(n)。
仅使用一个抽象关键比较运算的排序算法总平均上总是至少需要O(nlogn)。
内存使用量(以及其他电脑资源的使用)稳定度:稳定排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序。
也就是一个排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前。
一般的方法:插入、交换、选择、合并等等。
交换排序包含冒泡排序和快速排序。
关于各种排序方法的比较
各种排序方法的总结一.直接插入排序1.时间复杂度移动次数和比较次数受初始排列的影响。
最好情况o(n) 最坏情况o(n2) 平均情况o(n2)2.空间复杂度:o(1)3.算法特点稳定排序;算法简便,且容易实现适用于顺序和链式两种存储结构,链式存储时不需要移动记录,只修改指针;适合于初始记录基本有序的情况;当记录无序,且n较大时,不宜采用。
二.折半插入排序1.时间复杂度移动次数受初始排列的影响。
最好情况o(nlog2n) 最坏情况o(n2) 平均情况o(n2)2.空间复杂度o(1)3.算法特点稳定排序;算法简便,且容易实现只适用于顺序存储结构,不能用于链式存储结构;适合记录无序、n较大的情况;三.希尔排序1.时间复杂度2.空间复杂度o(1)3.算法特点不稳定排序,记录跳跃式的移动;只适用于顺序存储结构,不能用于链式存储结构;增量序列可以有多种取法,最后一个增量值必须是1;适合记录无序、n较大的情况;四.冒泡排序1.时间复杂度移动次数和比较次数受初始排列的影响。
最好情况o(n) 最坏情况o(n2) 平均情况o(n2)2.空间复杂度o(1)3.算法特点稳定排序;适用于顺序存储结构和链式存储结构;适合记录无序、n较大时不宜采用;五.快速排序1.时间复杂度移动次数和比较次数受初始排列的影响。
最好情况o(nlog2n) 最坏情况o(n2) 平均情况o(nlog2n)2.空间复杂度:o(log2n) 递归算法3.算法特点不稳定排序;算法简便,且容易实现适用于顺序存储结构;适合记录无序,且n较大情况。
六.直接选择排序1.时间复杂度比较次数不受初始排列的影响,移动次数受影响。
最好情况o(n2) 最坏情况o(n2) 平均情况o(n2)2.空间复杂度o(1)3.算法特点不稳定排序;适用于顺序存储结构和链式存储结构;移动记录的次数较多,适合记录占用空间较多时,采用此方法;七.堆排序1.时间复杂度移动次数和比较次数受初始排列的影响。
1.折半插入排序
if LT(L.r[0].key,L.r[m].key) high=m-1; //插入点在低半区。
else low=m+1; //插入点在高半区。
printf("(%4d,%4d,%4d)",low,high,m);
--i= 6,key=-858993460,otherinfo=-52--
--i= 7,key=-858993460,otherinfo=-52--
--i= 8,key=-858993460,otherinfo=-52--
--i= 9,key=-858993460,otherinfo=-52--
printf("------------------after_set_[main_l.length]--\n");
main_l.length =8;
printf("--main_l.length=%d--\n",main_l.length);
for(i=0;i<15;i++)
low=1;high=i-1;
while(low<=high) //在r[low..high]中折半查找有序插入的位置。
{
m=(low+high)/2 //折半。
if LT(L.r[0].key,L.r[m].key) high=m-1; //插入点在低半区。
else low=m+1; //插入点在高半区。
printf("\n");
for(i=2;i<=L.length;++i)
详解排序算法(一)之3种插入排序(直接插入、折半插入、希尔)
详解排序算法(⼀)之3种插⼊排序(直接插⼊、折半插⼊、希尔)直接插⼊排序打过牌的⼈都知道,当我们拿到⼀张新牌时,因为之前的牌已经经过排序,因此,我们只需将当前这张牌插⼊到合适的位置即可。
⽽直接插⼊排序,正是秉承这⼀思想,将待插⼊元素与之前元素⼀⼀⽐较,从⽽找到合适的插⼊位置。
那么使⽤直接插⼊排序,具体是怎样操作的呢?我们取 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 来进⾏⽰范。
(1)第1轮排序,3之前⽆可⽐较值,因此我们从44开始操作,取44和3⽐较,⼤于3,顺序保持不变。
得数据3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48(2)第2轮排序,取38和44⽐较,38 < 44,再将38与3⽐较,38 > 3,故将38放于第2位,得数据3, 38, 44, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48(3)第3轮排序,取5与44⽐较,5 < 44,再将5与38⽐较,5 < 38,再将5与3⽐较,5 > 3, 置于第2位,得数据3, 5, 38, 44, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48(4)如此经过14轮排序后,得到最终结果2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50动态图javascript实现function directInsertSort (arr) {let compare, // 对⽐元素下标current // 待插⼊元素值for (let i = 1; i < arr.length; i++) {current = arr[i]compare = i - 1while (current < arr[compare] && compare >= 0) {arr[compare + 1] = arr[compare]compare--}arr[compare + 1] = current}return arr}折半插⼊排序细⼼的同学可能已经注意到,当我们要将⼀个元素插⼊合适的位置时,其之前的元素是有序的,因此,我们可以⽤折半查找的⽅式来⽐对并插⼊元素,也就是所谓的折半插⼊排序。
折半插入排序报告
实习报告——“折半插入排序”演示程序(一)、程序的功能和特点主要实现的功能:1.折半插入排序;2.显示线性表;(二)、程序的算法设计“折半插入法”算法:1.【逻辑结构与存储结构设计】逻辑结构:线性表存储结构:内存中连续的存储结构2.【基本操作设计】从文本文件读入数据,输出显示数据;折半插入排序后在进行输出3. 【算法设计】基本思想:设在顺序表中有一个对象序列V[0],V[1],...,V[n-1].其中V[0],V[1],...V[i-1]是已经排好序的对象。
在插入V[i]时,利用折半搜索法寻找V[i]的插入位置。
假设排好的顺序是从小到大Left Middle Right若待排序元素的关键字>中间元素的关键字Left=Middle+1 Right反之:Right=Middle-1;这样一直重复对比寻找,知道Right>left时结束找到插入位置Left后,依次移动后边的每个元素,空开插入位置,进行插入;4.【高级语言代码】//成员方法:折半插入法排序public void BineryInsSort(){Record temp;//临时存放记录int Left,Right,Middle;//指向待排序列两端的下标/** 第一个数据已经排好,从第二个数据起* 逐个插入到已经排好的序列*/for(int i=1;i<CurrentSize;i++){Left=0;Right=i-1;temp=Vector[i];//备份要插入的数据//寻找插入位置Middlewhile(Left<=Right){//折半,插入中点Middle=(Left+Right)/2;if(temp.key>Vector[Middle].key)Right=Middle-1;//在左半区间找else Left=Middle+1;//在右半区间找}//结束时Left>Right//找到插入位置Left,后移空开插入位置for(int k=i-1;k>=Left;k--)Vector[k+1]=Vector[k];Vector[Left]=temp;//插入空位}//循环结束,所有数据读入}//显示线性表public void display(){double s=0.0;for(int i=0;i<CurrentSize;i++){//其余数据列System.out.print(Vector[i].other.stu_num+" ");System.out.print(Vector[i]+" ");System.out.print(Vector[i].other.sex+" ");System.out.print(Vector[i].other.age+" ");//排序关键字System.out.println(Vector[i].key+" ");s+=Vector[i].key;}System.out.println("平均分="+s/CurrentSize);}(三)、程序中类的设计“DataList”类:1.【主要成员变量说明】private static int DefaultSize=100;private Record Vector[];//线性表private int MaxSize,CurrentSize;//最大长度与当前长度2.【主要成员方法说明】//交换两记录public void swap(int i,int j){}//成员方法:折半插入法排序public void BineryInsSort(){}//成员方法:折半插入法排序public void BineryInsSort(){}//显示线性表public void display(){}4.【高级语言代码】package study_3;import java.io.*;//"待排表"类(多行数据构成的线性表)public class DataList {private static int DefaultSize=100;private Record Vector[];//线性表private int MaxSize,CurrentSize;//最大长度与当前长度//构造函数:从文件建表public DataList (String filename){MaxSize=DefaultSize;CurrentSize=0;Vector=new Record[MaxSize];//对象数组for(int i=0;i<MaxSize;i++)Vector[i]=new Record();//数组元素初始化try{//创建文件输入流File f=new File(filename);FileInputStream fin=new FileInputStream(f);//创建数据输入流,二者关联DataInputStream din=new DataInputStream(fin);byte c=0;byte temp[]=new byte[100];int len=0;String s;len=0;while((c=din.readByte())!=13){//遇到回车符temp[len]=c;//记录数是文本,非二进制数len++;//读取长度加1}s=new String(temp,0,len);int rs=Integer.parseInt(s);//字符串转整数din.skipBytes(1);//跳过换行符(ASII码11)while(CurrentSize<rs){//输入流结束时len=0;while((c=din.readByte())!='\t'){//读取字符temp[len]=c;//接收内容len++;//读取长度加1}s=new String(temp,0,len);//学号装入数组Vector[CurrentSize].other.stu_num=new String(temp,0,len);len=0;while((c=din.readByte())!='\t'){ // 读取字符temp[len] = c;// 接收内容len++ ;// 读取长度加1}s=new String(temp,0,len);//姓名装入数组Vector[CurrentSize]= s;len=0;while((c=din.readByte())!='\t'){ // 读取字符temp[len] = c;// 接收内容len++ ;// 读取长度加1}s=new String(temp,0,len);//性别装入数组Vector[CurrentSize].other.sex= s;//读出年龄len=0;while((c=din.readByte())!='\t'){ // 读取字符temp[len] = c;// 接收内容len++ ;// 读取长度加1}s=new String(temp,0,len); //字符串转整数Vector[CurrentSize].other.age=Integer.parseInt(s);//读出考试分数len=0;while((c=din.readByte())!=13){ // 读取字符temp[len] = c;// 接收内容len++ ;// 读取长度加1}s=new String(temp,0,len);din.skipBytes(1); //跳过换行字符Vector[CurrentSize].key=Double.parseDouble(s);CurrentSize++; //字符串转实数}//输入流结束din.close();//关闭数据流同时关闭文件流}catch(IOException e){System.out.println("文件异常");}}//交换两记录public void swap(int i,int j){Record temp=Vector[i];Vector[i]=Vector[j];Vector[j]=temp;}//成员方法:折半插入法排序public void BineryInsSort(){Record temp;//临时存放记录int Left,Right,Middle;//指向待排序列两端的下标/** 第一个数据已经排好,从第二个数据起* 逐个插入到已经排好的序列*/for(int i=1;i<CurrentSize;i++){Left=0;Right=i-1;temp=Vector[i];//备份要插入的数据//寻找插入位置Middlewhile(Left<=Right){//折半,插入中点Middle=(Left+Right)/2;if(temp.key>Vector[Middle].key)Right=Middle-1;//在左半区间找else Left=Middle+1;//在右半区间找}//结束时Left>Right//找到插入位置Left,后移空开插入位置for(int k=i-1;k>=Left;k--)Vector[k+1]=Vector[k];Vector[Left]=temp;//插入空位}//循环结束,所有数据读入}//显示线性表public void display(){double s=0.0;for(int i=0;i<CurrentSize;i++){//其余数据列System.out.print(Vector[i].other.stu_num+" ");System.out.print(Vector[i]+" ");System.out.print(Vector[i].other.sex+" ");System.out.print(Vector[i].other.age+" ");//排序关键字System.out.println(Vector[i].key+" ");s+=Vector[i].key;}System.out.println("平均分="+s/CurrentSize);}public static void main(String[] args) {//读入数据,把成绩作为排序关键字DataList D=new DataList("student.txt");D.display();//显示线性表D.BineryInsSort();//折半插入法排序D.display();}}(四)、程序的输入输出和运行结果截屏。
数据结构课程的内容
空间效率: O(1) 稳定性:稳定
23
折半插入排序算法
void BiInsertSort(SqList *L)
{ int i,j, low,high,m;
for(i=2;i<=L->length;i++)
{ L->r[0]=L->r[i]; low=1; high=i-1;
(KCN)和对象移动次数(RMN)分别为:
比较次数:n i = (n +2)(n -1)
i=2
2
移动次数:n(i +1)= (n +4)(n -1)
i=2
2
时间复杂度为O(n2)。
54 32 1 44 5 3 2 1 33 4 5 2 1 22 3 4 5 1 11 2 3 4 5
比较i次(依次与前面的i-1个记录进行比较,并和哨兵比较1次),移动i+1次(前面的i-1个记录依次向后移动,另外开始 19
13
*表示后一个25
例2:关键字序列T= (21,25,49,25*,16,08),
请写出直接插入排序的具体实现过程。 解:假设该序列已存入一维数组V[7]中,将V[0]作为缓冲或
暂存单元(Temp)。则程序执行过程为:
初态:
完成!
22410暂存59685*
021816
21516
2425951*
2459*
定义:
设有记录序列:{ R1、R2………Rn } 其相应的 关键字序列为: { K1、K2………Kn }; 若存在一种 确定的关系:Kx<=Ky<=…<= Kz则将记录序列 { R1、 R2……….Rn}排成按该关键字有序的序列: { Rx、 Ry……….Rz}的操作,称之为排序。
C语言最常用的六种排序方法详解
1.冒泡排序:
2.简单选择排序:
3.快速排序:
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。
4.直接插入排序:
5.折半插入排序:
折半插入排序(binary insertion sort)是对插入排序算法的一种改进,在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为
a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
代码:
6.希尔排序:。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
折半插入排序算法:也叫二分插入排序算法。
这种算法和直接插入算法基本一样。
都是属于插入排序。
所以时间复杂度为N2,空间复杂度为1.最好情况时间复杂度是n。
先看看这种算法思想。
折半插入算法与直接插入不同是:不是比的过程,那是插的过程。
二分排序想名字就是把有序的东西分成2半。
比如说你向1 2 3 4 5 6这个有序序列插入4,你怎么插,你可以先和6比,在和5比这样可以做。
但是作为一个有序序列你如果和中间比,如果比中间大就和后面那一部分比,然后后面又找中间部分。
在平均的情况下比直接插这比要快。
例如:有一个数要排列
97 6 4 5 1 5 7
第一趟排,就找第二个数看看和前一个数的大小,然后确定插入的位置
7 96 4 5 1 5 7 后面同理
6 7 94 5 1 5 7
4 6 7 9
5 1 5 7
4 5 6 7 91 5 7
1 4 5 6 7 957
1 4 5 5 6 7 97
1 4 5 5 6 7 7 9
看这个排序过程和直接插入排序一模一样只是代码实现上是不同的。
不同在向有序序列插入的过程。
大家看看实现代码:
package com.fish.sort;
public class MiddleInsertSort {
public static void main(String[] args) {
int[] array = new int[] { 9, 7, 6, 4, 5, 1, 5, 7 };
myResult(array);
}
public static void myResult(int[] array) {
for (int i = 1; i < array.length; i++) {
// 比较当前数和前一个数的大小
if (array[i] < array[i - 1]) {
// 后一个数比前一个数小,就把后面的大数放一个交换区
int swap = array[i];
// 定义高低位是用来确定,前面有序序列的大小。
low表示有序序列的其实位置,high表示有序序列的末尾。
这样的
// 这的作用是,当你的数要插的时候只要往有序序列里面查就行了。
前面这些都和直接排序没有不同。
int low = 0;
int high = i - 1;
// 下面的循环才是和直接插入不同的。
因为直接插入排序是从后往前一个个比较,但是如果试想这个是是最小的你得比i-1次。
// 因为是有序序列,那么我先和中间比。
如果比中间大,我的范围就往后找。
每次都和中间比。
这样在平均情况下要比直接排序找的快。
while (low <= high) {
int mid = (low + high) / 2;
if (array[mid] < swap) {
low = mid + 1;
} else {
high = mid - 1;
}
}
// 将low~i处数据整体向后移动1位
for (int j = i; j > low; j--) {
array[j] = array[j - 1];
}
array[low] = swap;
}
}
System.out.println("结果是:");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
}
我想我讲的够清楚了。