冒泡排序
冒泡排序的基本思想:通过无序区中相邻记录关键字间的比较和位置的交换,使关键字最小的记录如气泡一般逐渐往上“漂浮”直至“水面”。
整个算法是从最下面的记录开始,对每两个相邻的关键字进行比较,且使关键字较小的记录换至关键字较大的记录之上,使得经过一趟冒泡排序后,关键字最小的记录到达最上端,接着再在剩下的记录中找关键字次小的记录,并把它换在第二个位置上。依次类推,一直到所有记录都有序为止。
**若有 n个数据元素,则比较次数为:(n-1)n/2
交换次数:
如果序列本身有序,无需交换
如果序列本身倒序,交换(n-1)n/2
因此,冒泡排序的时间复杂度为O(n^2)
2)稳定性
#include "stdafx.h"
#include<iostream>
#include<string>
using namespace std;
// 冒泡排序
int main()
{
int list[10] = { 56,98,10,84,19, 53,68,73,34,71 };
int length = sizeof(list) / sizeof(list[0]);//求数组长度
cout << length << endl;
//-----------------------------------------------
for (int i = 0; i < length-1; i++)
{
for (int j = 0; j < length-1-i; j++)
{
if (list[j]>list[j+1])
{
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
for (int i = 0; i < length; i++)
{
cout << list[i]<<" ";
}
return 0;
}
插入排序
假设待排序的记录存放在数组R[0…n-1]中,排序过程的某一中间时刻,R被划分成两个子区间R[0…i-1]和R[i…n-1],其中:前一个子区间是已排好序的有序区,后一个子区间则是当前未排序的部分,不妨称其为无序区。
直接插入排序的基本操作是将当前无序区的第1个记录R[i]插入到有序区R[0…i-1]中适当的位置上,使R[0…i]变为新的有序区。
**1)时间复杂度
若有 n个数据元素序列
如果序列本身有序,比较n-1次,交换0次
如果序列本身倒序,比较(n-1)n/2次,交换(n-1)n/2次
所以插入排序的时间复杂度为O(n2),最优复杂度为O(n)
2)稳定性
#include "stdafx.h"
#include<iostream>
#include<string>
using namespace std;
int main()
{
int list[10] = { 56,98,10,84,19, 53,68,73,34,71 };
int length = sizeof(list) / sizeof(list[0]);//求数组长度
cout << length << endl;
int key = 0;//监视哨
for (int i = 0; i < length; i++)
{
for (int j = i-1; j >=0; j--) //******
{
if (list[j+1]>list[j])
{
key = list[j + 1];
list[j + 1] = list[j];
list[j] = key;
}
}
}
for (int i = 0; i < length; i++)
{
cout << list[i] << " ";
}
return 0;
}
希尔 排序
希尔排序:希尔排序又称为缩小增量排序,它是一种插入排序。其基本思想是:
把记录按步长(增量)分组,对每组记录采用插入排序方法进行排序;
随着步长逐渐缩小,所分成的组包含的记录越来越多,当步长的值减到1时,整个数据合成为一组;
增量序列的选择一般依据下面两点:
1)最后一个增量必须为1;
2)应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
希尔排序的时间性能优于直接插入排序的原因:
1)当数据有序时,插入排序所需的比较和移动次数均较少,复杂度为O(n)。
2)在希尔排序分组,每组的记录数目少,使用插入排序速度快,当增量为1时,数据又接近有序,速度自然快了。因此,希尔排序在效率上较直接插人排序有较大的改进。平均时间复杂度为O(n^2)。
因为以增量跳跃分组排序,所以希尔排序不稳定。
#include <iostream>
#include<string>
using namespace std;
/*数组遍历*/
void ListShow(int list[],int length){
for(int i=0;i<10;i++){
cout<<list[i]<<" ";
}
cout<<endl;
}
void ShellSort(int *list,int len){
int incream=len;//增量
int i,j;
int key=0;
do{
incream=incream/3;
for(i=incream;i<len;i++){
if(list[i]<list[i-incream]){
key=list[i];
for(j=i-incream;j>=0&&key<list[j];j-=incream){
list[j+incream]=list[j];
list[j]=key;
}
}
}
}while(incream>1); cout<<"结果:";
ListShow(list,len);
}
int main()
{
int list[10]={56,98,10,84,19, 53,68,73,34,71};
int length=sizeof(list)/sizeof(list[0]);//求数组的长度,C++固定方式
ListShow(list,length);
ShellSort(list,length);
return 0;
}
快速排序
快速排序的基本思想:在待排序的n个记录中任取一个记录,把该记录放入适当位置后,数据序列被此记录划分成两部分。所有关键字比该记录关键字小的记录放置在前一部分,所有比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。 首先对无序的记录序列进行“一次划分”,之后分别对分割所得两个子序列“递归”进行快速排序。
设待排序的表有10个记录,其关键字分别为{6,8,7,9,0,1,3,2,4,5},采用快速排序方法进行排序的详细过程如下图所示。
排序步骤:
1**)选取6为key,先从尾部(high指针)开始查找比key小的数与key交换,然后从头部(low指针)开始查找比key大的数与key交换,交替进行,直到high指针和low指针相遇,第一趟排序结束,由key将序列分成左右两个子序列,左边都比key小,右边都比key大。
2)以同样的方法排序左子序列,直到左子序列有序。
3)再以同样的方法排序右子序列,直到右子序列有序。**
)时间复杂度
现有 n个数据元素序列
首先对整个数列所有元素都比较一次,分成两个序列,比较的次数为n
然后再对这两个子序列排序,假设子序列时间排序为O(n/2)
则n个元素的时间复杂度=
<=2O(n/2)+n
<=2(2(O(n/4))+n/2))+n=4O(n/4)+2n
<=2(2(2(O(n/8))+n/4)+n/2))+n=8O(n/8)+3n
……
<=n(O(1))+nlog2^n (O(1)=0)
<= nlog2^n
快速排序的时间复杂度为:O(nlog2^n)
2)稳定性
在实施快速排序的过程中,相同元素的顺序过能会因为在左右两个序中不断的改变位置,因此最后的排序结果相同元素的位置有可能发生变化,因此快速排序算法是不稳定的。