冒泡排序
Posted ylc0x01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了冒泡排序相关的知识,希望对你有一定的参考价值。
纸上得来终觉浅,绝知此事要躬行
汇编实现及推导过程
;程序名称:
;功能:冒泡排序,方法5:不用两两比较,第一位数和其余数比较,小就交换
;=======================================
assume cs:code,ds:data
;排序
;手推算法;
;外层循环条件 si=0;si<len-1;si++
;内层循环条件 di=si+1;di<=len-1;di++
;算法:不用两两比较,第一位数和其余数比较,小就交换
;初始数据: 6,5,4,3,2,1
;si = 0 bi =1 5,6,4,3,2,1
;si = 0 bi =2 4,6,5,3,2,1
;si = 0 bi =3 3,6,5,4,2,1
;si = 0 bi =4 2,6,5,4,3,1
;si = 0 bi =5 1,6,5,4,3,2
;si = 1 bi =2 1,5,6,4,3,2
;si = 1 bi =3 1,4,6,5,3,2
;si = 1 bi =4 1,3,6,5,4,2
;si = 1 bi =5 1,2,6,5,4,3
;si = 2 bi =3 1,2,5,6,4,3
;si = 2 bi =4 1,2,4,6,5,3
;si = 2 bi =5 1,2,3,6,5,4
;si = 3 bi =4 1,2,3,5,6,4
;si = 3 bi =5 1,2,3,4,6,5
;si = 4 bi =5 1,2,3,4,5,6
data segment
vals db 2,1,-1 ;准备的有符号数,两正两负
len = $-vals-1 ;len保存循环次数
data ends
code segment
start:
mov ax,data ;初始化数据段
mov ds,ax
;准备
mov si,-1 ;外层循环指针
;外层循环
loop1:
inc si ;外层循环指针+1
cmp si,word ptr len ;判断是否循环完成
jnb over
mov di,si ;初始化内层指针
;内层循环
loop2:
inc di ;内层循环指针
cmp di,word ptr len ;判断是否循环完成
ja loop1 ;继续外层循环
xor ax,ax
MOV al,vals[si] ;di处的值放入ax中
MOV ah,vals[di] ;di+1处的值放入dx中
cmp al,ah ;比大小
jnl swap ;ax>dx,两个值交换
jmp loop2 ;继续内层循环
;数据交换
swap:
xchg al,ah ;ax与dx的值交换
MOV vals[si],al ;ax的值放回到变量中
MOV vals[di],ah ;dx的值放回变量中
jmp loop2 ;继续内层循环
over:
mov ax,4c00h ;dos中断
int 21H
code ends
end start
高级语言实现
void swap(int* x, int* y)
int tmp = *x;
*x = *y;
*y = tmp;
void bubble(int hands[], int size)
for (int i = 0; i < size - 1; i++)
for (int j = 0; j < size - i - 1; j++)
if (hands[j] > hands[j + 1])
swap(&hands[j], &hands[j + 1]);
int main(void)
bubble(_, _);
return 0;
拓扑排序(图)、冒泡排序、插入排序
参考技术A AOV网络(Activity On Vertex)拓扑序:如果在图中从V到W有一条有向路径,则V一定排在W之前。满足此条件的顶点序列称为一个拓扑序
获得一个拓扑序的过程就是拓扑排序
AVO如果有合理的拓扑序,则必定是有向无环图(Directed Acyclic Graph,DAG)
算法:
void TopSort ( )
for ( cnt = 0 ; cnt < [ V ] ; cnt ++ )
V = 未输出的入度为0的顶点 ;
if ( 这样的V不存在 )
Error ( “图中有回路” ) ;
break ;
输出V,或者纪录V的输出序号;
for ( V 的每个邻接点 W )
Indegree [ W ]--;
改进:随时将入度变为0的顶点放到一个容器里
void TopSort ( )
for ( 图中每个顶点 V )
if ( Indegree [ W ] == 0 )
Enqueue ( V , Q ) ;
while ( ! IsEmpty ( Q ) ) ;
V = Dequeue ( Q ) ;
输出V,或者纪录V的输出序号;
cnt ++; // 计数器,纪录顶点数量
for ( V 的每个邻接点 W )
if ( —Indegree [ W ] == 0 ) //如果减完后入度为0,则将其放入容器中
Enqueue ( W , Q ) ;
if ( cnt != [ V ] )
Error ( “图中有回路” );
时间复杂度 T = O( |V| + |E| )
此算法可以用来检测有向图是否DAG
关键路径问题
AOE(Activity On Edge)网络
一般用于安排项目的工序,活动表示在边上,顶点代表活动的停止;边上写有活动持续时间
顶点包括:顶点编号、最早完成时间、最晚完成时间
两类基础算法,排序和查找
排序算法的前提前提:
void X_Sort ( ElementType A [ ], int N )
1.大多数情况下,为简单起见,讨论从小到大的整数排序
2.N是正整数,只讨论基于比较的排序(> = < 是有定义的)
3.只讨论内部排序:内存空间充分大,排序在内部空间中完成
4.稳定性:任意两个相等的数据,排序前后的相对位置不发生改变
5.没有一种排序算法是任何情况下都表现最好的
void Bubble_Sort ( ElementType A[ ] , int N )
for ( P = N - 1 ; P >= 0 ; P — )
flag = 0 ;
for ( i = 0 ; i < p ; i ++ ) // 一趟冒泡
if ( A[ i ] > A[ i + 1 ] ) // 比较相邻两个元素的大小
Swap ( A[ i ] , A[ i + 1 ] ) ;
flag = 1 ; // 标识发生了交换
// 思考:假设当程序执行到某一步时 数据已经是有序的了,但此时程序是不知道的,所以还要判断
if ( flag == 0 ) break ; // 全程无交换 数据已经有序 不需要再进从排序
最好情况:顺序 T = O ( N )
最坏情况:逆序 T = O ( N的平方 )
由于是单向执行,比较相邻的两个元素,所以适用于链表存储的数据
当两个数据相等,冒泡排序的比较过程中没有将它们交换位置,所以改算法是稳定的
void Insertion_Sort ( ElementType A[ ] , int N )
for ( P = 1 ; P < N ; P ++ ) // 假设第0个元素已经存在,从第一个元素开始插入
Tmp = A[ P ] ; // 下一个元素
for ( i = P ; i > 0 && A[ i - 1 ] > Tmp ; i -- ) // 需要插入的新元素当前从最后那个元素开始比起,比到第一个元素
A[ i ] = A[ i - 1 ] ; // 移除空位
A[ i ] = Tmp ; // 新元素落位
最好情况:顺序 T = O ( N )
最坏情况:逆序 T = O ( N的平方 )
冒泡元素是两两交换 需要涉及到三步,插入排序元素向后错,新元素一次放入
逆序对:对于下标 i < j,如果A[ i ] > A[ j ],则称 ( i , j )是一对逆序对
每一次交换元素正好消去一个逆序对,序列中有多少个逆序对,就需要交换几次元素
时间复杂度下界:
插入排序:T( N , I ) = O( N + I ) 其中 I 是逆序对个数,如果序列基本有序,则插入排序简单且高效
定理:任意N个不同元素组成的序列平均有 N(N-1)/4 个逆序对。
定理:任何仅以交换相邻元素来排序的算法,其平均时间复杂度的下界为N平方
要提高算法效率,我们必须:每次交换不止消去一个逆序对,所以我们每次交换相隔较远的两个个元素
以上是关于冒泡排序的主要内容,如果未能解决你的问题,请参考以下文章