冒泡排序
冒泡排序举例说明
假设要对[4,2,7,1,3]进行排序
- 第一步:比较4和2的值,4比2大,
- 第二步:交换顺序4和2顺序,为[2,4,7,1,3]
- 第三步:比较4和7,4比7小(不用交换顺序)
- 第四步:比较7和1,7比1大
- 第五步:交换顺序7和1顺序,为[2,4,1,7,3]
- 第六步:比较7和3,7比3大
- 第七步:交换顺序7和3顺序,为[2,4,1,3,7]
经过7步操作之后,我们把最大的元素[7],换到了最右边,这也是算法名为冒泡排序的原因:每一次轮回过后,未排序的值最大元素都会被“冒泡”到最右边。以上的7步操作只是第一轮,还要经过4轮,数组才会被排序好为[1,2,3,4,7]
冒泡排序算法代码实现
//冒泡排序算法
int[] numbers=new int[]{4,2,7,1,3};
for(int i=0;i<numbers.length-1;i++)
{
for(int j=0;j<numbers.length-1-i;j++)
{
if(numbers[j]>numbers[j+1])
{
int temp=numbers[j];
numbers[j]=numbers[j+1];
numbers[j+1]=temp;
}
}
}
冒泡排序效率
冒泡排序的执行步骤分为两步:1.比较 2.交货顺序
经过四轮比较:4+3+2+1=10,若为N个元素,需要 (N-1)+(N-2)+...+1次比较; 经过最坏的情况,每次比较都要排序,也是(N-1)+(N-2)+...+1次比较,所以总共步数是N²-N,记为O(N²)
选择排序
选择排序举例说明
假设要对[4,2,7,1,3]进行排序
- 第一步:将索引0和索引1的值比较,即4和2的值,4比2大,最小值为2
- 第二步:7与2比较,最小值为2
- 第三步:1与2比较,更新最小值为1
- 第四步:3与1比较,最小值为1
- 第五步:将1与4进行交换,顺序为[1,2,7,4,3]
经过5步操作之后,我们把最小的元素[1],换到了最左边,还要经过4轮,数组才会被排序好为[1,2,3,4,7]
选择排序算法代码实现
//选择排序算法
int[] arr=new int[]{4,2,7,1,3};
for(int i = 0; i < arr.length - 1; i++) {// 做第i趟排序
int k = i;
for(int j = k + 1; j < arr.length; j++){// 选最小的记录
if(arr[j] < arr[k]){
k = j; //记下目前找到的最小值所在的位置
}
}
//在内层循环结束,也就是找到本轮循环的最小的数以后,再进行交换
if(i != k){ //交换a[i]和a[k]
int temp = arr[i];
arr[i] = arr[k];
arr[k] = temp;
}
}
选择排序效率
选择排序的执行步骤分为两步:1.比较 2.交货顺序,但是与冒泡排序不同的是,在最坏的情况下,每轮的交换最多只有一次,若元素为N个,则需要需要 (N-1)+(N-2)+...+1次比较,总共步数为N²/2+N-1,记为O(N²/2)
插入排序
插入排序举例说明
假设要对[4,2,7,1,3]进行排序
- 第一轮准备工作:将索引1的值[2]移走,并将值存在临时变量tempValue中;
- 第一步:4与tenmpValue[2]比较,4大于2
- 第二步:将4右移
- 第三步:将tempValue值,插回数组,顺序为[2,4,7,1,3],结束第一轮
- 第二轮准备工作:将索引2的值[7]移走,并将值存在临时变量tempValue中;
- 第四步:4与tenmpValue[7]比较,4小于7无需平移
- 第五步:将tempValue值插回原有空隙,顺序为[2,4,7,1,3],结束第二轮
- 第三轮准备工作:将索引3的值[1]移走,并将值存在临时变量tempValue中;
- 第六步:7与tenmpValue[1]比较
- 第七步:7比1大,往右平移一位
- 第八步:4与tenmpValue[1]比较
- 第九步:4比1大,往右平移一位
- 第十步:2与tenmpValue[1]比较
- 第十一步:2比1大,往右平移一位
- 第十二步:到了数组最左端,无值比较,将tempValue插入,结束第三轮,顺序为[1,2,4,7,3]
- 第四轮准备工作:将索引4的值[3]移走,并将值存在临时变量tempValue中;
- 第十三步:7与tenmpValue[3]比较
- 第十四步:7比3大,往右平移一位
- 第十五步:4与tenmpValue[3]比较
- 第十六步:4比3大,往右平移一位
- 第十七步:2与tenmpValue[3]比较
- 第十八步:2比tenmpValue[3]小,插回空隙,顺序为[1,2,3,4,7]
插入排序算法代码实现
//插入排序算法
for(int index = 1; index<length; index++){//外层向右的index,即作为比较对象的数据的index
int temp = array[index];//用作比较的数据
int leftindex = index-1;
while(leftindex>=0 && array[leftindex]>temp){//当比到最左边或者遇到比temp小的数据时,结束循环
array[leftindex+1] = array[leftindex];
leftindex--;
}
array[leftindex+1] = temp;//把temp放到空位上
}
插入排序效率
插入排序分为4中步骤:1.移除 2.比较 3.平移 4.插入 在最坏的情况下,平移和比较的次数一样,为: (N-1)+(N-2)+...+1,即N²-N/2;插入和移除的次数一样,都为N-1.所以总共的次数为N²+N-2,记为O(N²)
冒泡排序、选择排序、插入排序比较
| 排序算法 | 总共步数 | O计数 |
|---|---|---|
| 冒泡排序 | N²-N | O(N²) |
| 选择排序 | N²/2+N-1 | O(N²/2) |
| 插入排序序 | N²+N-2 | O(N²) |
以上我们讨论的是最坏情况,但是在现实生活中,我们考虑的是平均情况,具体情况使用算法,如果能够确信数组是大致有序的,则用插入排序会更好些,大致逆序,则用选择排序。如果不能确定的话,则两种都可以
快速排序
快速排序依赖于分区算法,步骤如下:
- 左指针逐个向右移动,当遇到大于或等于轴的值时,停下来
- 右指针逐个向、左移动,当遇到小于或等于轴的值时,停下来
- 将两针所指的值交换位置
- 重复以上步骤,直致两指针重合
- 将轴与左指针的值交换位置
快速排序举例说明
假设要对[4,2,7,1,3]进行排序
- 准备工作3为轴,左指针为4,1为右指针
- 第一步:左指针[4]比轴[3]大,不动
- 第二步:右指针[1]比轴[3]小,不动
- 第三步:左右指针停止,交换位置,顺序为[1,2,7,4,3],3为轴,左指针为1,右指针为4
- 第四步:左指针[1]比轴[3]小
- 第五步:右移左指针,左指针为[2]
- 第六步:左指针[2]比轴[3]小
- 第七步:右移左指针,左指针为[7]
- 第八步:左指针[7]比轴[3]大,不动
- 第九步:右指针[4]比轴[3]大,右指针左移
- 第十步:两个指针指向同一个值[7],交换左指针[7]和轴[3]的位置,顺序为[1,2,3,4,7]
快速排序算法代码实现
//快速排序算法
private static void quickSort(Integer[] arr, int low, int high) {
if(low < high){
int part=partition(arr,low,high);
//递归调用
quickSort(arr,low,part-1);
quickSort(arr,part+1,high);
}
}
//分区算法实现
private static int partition(Integer[] arr, int low, int high) {
//使用 r[low]作为枢轴元素
int pivot = arr[low];
//从两端交替向内扫描
while(low < high){
while(low<high && arr[high] >= pivot) {high--;}
//将比 pivot 小的元素移向低端
arr[low] = arr[high];
while(low<high && arr[low] <= pivot){low++;}
//将比 pivot 大的元素移向高端
arr[high] = arr[low];
}
//设置枢轴
arr[low]=pivot;
//返回枢轴元素位置
return low;
}
快速排序效率
| 排序算法 | 最好情况 | 平均情况 | 最坏情况 |
|---|---|---|---|
| 插入排序 | O(N) | O(N²) | O(N²) |
| 快速排序 | O(N㏒N) | O(N㏒N) | O(N²) |