一、冒泡排序
时间复杂度最好的时候O(n),最坏的时候O(nn)
最好的时候,只需要做n-1次比较,不需要移动,时间复杂度O(n)
最坏的时候,需要做(n-1)+(n-2)+…+2+1次比较,同时每次比较都需要交换一次,所以时间复杂度是O(nn)
void BubbleSort(int* numbers,int n)
{
int i,j;
///i=0时,经过冒泡线性表中最小的数会上升到第一位,要经过n次,才能完成整个排序过程
for(i=0;i<n;i++)
{
for(j=n-2;j>=i;j--)
{
if(numbers[j]>numbers[j+1])
swap(numbers[j],numbers[j+1]);///线性表末尾的两个数进行比较,然后不断上升
}
}
}
优化的冒泡排序
对于已经就是有序的数据,不再进行交换了,节省比较次数。
如果当i等于一个值时,此时线性表中没有任何数据交互,那说明整个线性表已经有序了。我们可以设置一个标志位
void BubbleSort2(int* numbers,int n)
{
int i,j;
bool flag=true;
for(i=0;i<n&&flag==true;i++) ///注意这里判断条件的不同
{
flag=false;
for(j=n-2;j>=i;j--)
{
if(numbers[j]>numbers[j+1])
{
swap(numbers[j],numbers[j+1]);
falg=true; ///只有有交换发生,才会设置flag为true。
}
}
}
}
二、选择排序
基本思想:每一趟在n-i个元素中找出最小的元素,例如i=0时,就在0~n-1之间找一个最小的数,i=1,再在1 ~n-1之间找出最小的数,直到i=n-i为止。
优势:交换移动数据次数特别少。
时间复杂度:O(nn)
比较的次数为(n-1)+(n-2)+…+2+1,交换的次数最好的情况下0次,最坏n-1次,综合时间复杂度还是O(nn)
void SelectSort(int* numbers,int n)
{
int i,j;
int min;
for(i=0;i<n;i++)
{
min=i;
for(j=i+1;j<n;j++)
{
if(numbers[min]>numbers[j])
min=j; ///记录下最小值的下标
}
if(i!=min)
swap(numbers[i],numbers[min]);
}
}
三、插入排序
时间复杂度O(n*n)
最好的时候,进行n-1次比较(比较前后两个数据谁大),所有数据都不用移动,时间复杂度O(n)
最坏的时候,比较次数2+3+…+n=(n+2)(n-1)/2,移动次数1+2+…n-1+n=(n+1)n/2, 总的时间复杂度为O(n)
void InsertSort(int* numbers,int n)
{
int i;j;
int a;
for(int i=1;i<n;i++) //从数组的第二个元素开始
{
if(numbers[i]<numbers[i-1]) //比第二个元素和第一个元素的大小,如果前面的比后面的大,说明前面的要后移
{
a=numbers[i]; //保存较小的数据
for(j=i-1;numbers[j]>a;j--) ///在numbers[i]之前,所有比他大的元素都要后移
{
numbers[j+1]=numbers[j];
}
numbers[j+1]=a; ///所有的后移结束之后,把较小的这个数插入到前头
}
}
}
四、希尔排序
跳跃式移动,提高排序效率。
时间复杂度是O(n的3/2次方)???
void ShellSort(int* numbers,int n)
{
int increment=n;
while(increment>0) ///缩小跨度,直到为零
{
increment=n/3+1; ///选定一个跨度
for(int i=increment+1;i<n;i++) ///如果后面的数比前面的数大,就交换二者位置
{
if(numbers[i]<numbers[i-increment])
{
swap(numbers[i],numbers[i-increment]);
}
}
}
五、堆排序
大顶堆:每个根节点的值都大于或等于其左右子节点的值。
小顶堆:每个根节点的值都小于或等于其左右子节点的值。
堆排序时间复杂度:O(nlogn)
///把一个序列调整为大顶堆
void HeadAdjust(int* numbers,int s,int n)
{
int temp;
temp=numbers[s]; ////s是需要调整的根节点
for(int j=2*s;j<n;j*=2) ///每次都在跟节点的左右子节点比较,所以j=j*2
{
if(j<n-1&&numbers[j]<numbers[j+1]) //左子节点小于右子节点
++j;
if(temp>numbers[j]) ///根节点值大于子节点值,跳出循环
break;
numbers[s]=numbers[j];//大的上去
s=j;
}
numbers[s]=temp; //等于交换了子节点的最大值和根节点
}
//堆排序
void HeadSort(int* numbers,int n)
{
int i;
for(i=n/2;i>0;i--) ///i=n/2,当有n个节点时,最底层的一个根节点就是n/2
HeadAdjust(numbers,i,n); //对每个根节点都调整
for(i=n-1,i>0;i--) ///排序过程,交换堆顶和最后一个节点的值,然后去掉最后一个节点,剩下的节点重新构造堆
{
swap(numbers[0],numbers[i];
HeadAdjust(numbers,0,i-1);
}
}
六、归并排序
拆成两两排序,然后合并
时间复杂度O(nlogn)
void MergeSort(int numbers[],int numbers1[],int s,int n)
{
int m;
int TR[MAXSIZE+1];
if(s==t)
TR=numbers[s];
else
{
m=(s+n)/2;
MergeSort(numbers[],TR,0,m);
MergeSort(numbers[],TR,m+1,n);
Merge(TR,numbers1[],s,m,n);
}
}
void Merge(int TR[],int numbers1[],int i,int m,int n)
{
int j,k.l;///k是numbers1的下标,i指向前一半,j指向后一半
for(j=m+1,k=i;i<=m&&j<n;k++)
{
if(TR[i]<TR[j])
numbers1[k]=TR[i++]; //先用i,后加1
else
numbers1[k]=TR[j++];
}
///将比较之后,剩下的部分加到后面
if(i<=m)
{
for(;i<=m;i++)
numbers1[k+1]=TR[i+1];
}
if(j<=n)
{
for(;j<=n;j++)
numbers[k+1]=TR[j+1];
}
}
七、快速排序
把待排序列分割成独立的两部分,其中一部分记录的关键字均比另一部分小,然后对这两部分再继续分,最终使整个序列有序。
时间复杂度:在二叉树比较均匀(分割出的两部分长度差不多)时,时间复杂度为O(nlogn),最坏情况下(极其不均匀),时间复杂度为O(n*n),平均时间复杂度为O(nlogn)。
void QuickSort(int numbers[],int n)
{
Qsort(numbers[],0,n-1);//从0到n-1
}
void Qsort(int numbers[],int low,int high)
{
int pivot;//中轴点
if(low<high)
{
pivot=Partition(numbers[],low,high);
Qsort(numbers[],low,pivot-1); ///递归会大量使用栈内存,深度过大时慎用
Qsort(numbers[],pivot+1,high);
}
}
int Partition(int numbers[],int low,int high)
{
int pivot;
/************
int m=(low+high)/2;
if(numbers[low]>numbers[high])
swap(numbers[low]>numbers[high];
if(number[m]>numbers[high])
swap(numbers[m],numbers[high]);
if(numbers[m]>numbers[low])
swap(numbers[m],numbers[low]); ////保证了numbers[low]是三个数里面中间大的
***************/
pivot=numbers[low]; ///此处可以改进选取规则,现在是那第一个数当成轴枢点,可以使用三数取中法改进
while(low<high)
{
while(low<high&&numbers[high]>=pivot)
high--;
swap(numbers[],low,high); ///这里也可以采用赋值而不是交换的方法
while(low<high&&numbers[low]<=pivot)
low++;
swap(numbers[],low,high);
}
return low;
}
///另一版本实现
void quickSort(int arr[],int startNum,int endNum)
{
if(startNum>=endNum)
return;
///k为初始基准值
int i=startNum,j=endNum,k=arr[i];
while(i<j)
{
///从后往前找小于k的第一个值
while(i<j && arr[j]>k)
j--;
if(i<j)
{
arr[i] = arr[j];
i++;
}
///从前往后找大于k的第一个值
while(i<j && arr[i]<k)
i++;
if(i<j)
{
arr[j] = arr[i];
j--;
}
}
arr[i] = k;
quickSort(arr,startNum,i-1);
quickSort(arr,i+1,endNum);
}