关于时间复杂度为O(N^2)的算法
其实时间复杂度为O(N^2)的算法是很缓慢的,但简单。
在用于规模小或者非常小的数组时,它们的简单使它们胜过快速但复杂的的算法。
案例都以数组为操作对象,实际还可以用于其他对象,例如堆栈和队列等。
插入排序
插入排序实际上把一个数组划分两种数组来看,一个是已经排好序的一个是未排序的(等待排序的)。
这种方式类似于玩扑克牌时候排序,拿一张排一张。
算法的伪代码方便我们去理解算法。
以下给插入排序的伪代码:
/*
* Insertionsort(Data: values[])
* For i=0 To <len of values>-1
* //将元素i移动到数组中已排序部分的合适位置上
* <找到第一个位置j,满足j <i 且 values[j]> values[i]>
* <将项移动到位置j>
* Next i
* End Insertionsort
*/
转换为C语言:
void Insertionsort(int *values,int len)//插入排序
{
for(int i=1;i<len;i++)//实际操作发现i不必等于0,因为在已排序的数组为空情况下,第一个元素只有一种排法
{
int j;
int temp=values[i];
for( j=i;j>0&&values[j-1]>temp;j--)
values[j]=values[j-1];
values[j]=temp;
}
}
案例详解
例如要排序: 5 2 4 6 1 3
第一次循环 i=1,也就是需要排2的位置。
通过观察可知如果要非递减的方法去排序,2应该放在5的前面。
代码将2通过临时变量temp储存起来。然后进入循环:
循环开始j=i(=1),条件为j>0(防止越界)&&values[j-1]>temp(找位置)
然后循环体为挪位置。
? 5 4 6 1 3 //(?代表空着位置)
最后把2放进对应的位置
2 5 4 6 1 3 //(粗体代表已排序的数组)
第二次结果
2 4 5 6 1 3
第三次结果
2 4 5 6 1 3
因为5>6在内层循环一开始就不满足条件,循环退出,6还是在原位。
第四次(细讲找位置)
第四次就要排1的位置,首先j是从1的位置开始,判断6是否大于1.也就是说判断前一个是否大于后一个,如果大于那么就说明该待排序的元素位置在和其比较元素的前面,那么循环体就会把6放在1的位置将原来的1覆盖,也就是空出来原本6的位置,这样就可以将1重新放入数组并且不覆盖已有的排好序的元素,最后j–也就是再一次往前去判断。
过程细节:(划掉的元素为当前比较的对象,例如一开始和6去比较)
2 4 5 6 1 3
2 4 5 ? 6 3
2 4 ? 5 6 3
2 ? 4 5 6 3
? 2 4 5 6 3
最后因为前面没元素可比较(意味着到第一位了),条件一不满足,跳出循环将1放入数组内。
第五次结果
1 2 3 4 5 6
选择排序
选择排序的基本思想是找到输入序列种包含的最大元素(或最小元素)并且将它加入到一个不断增长的已排序序列末端(或开端)。
伪代码展示:
/*
* Selectionsort(Data: values[])
* For i=0 To <len of values>-1
* //找到下标为i的元素
* <找到数组中满足j>=i的所有位置j中最小项>
* <交换values[i]和values[j]>
* Next i
* End Selectionsort
*/
转换成C语言:
void Selectionsort(int *values,int n)//选择排序
{
for(int i=0;i<n-1;i++)//最后自动归位所以可以变成n-1
{
int min=i;
for(int j=i+1;j<n;j++)
if(values[j]<values[min])
min=j;
if(min != i)//交换(判断需不需要)
{
int temp=values[min];
values[min]=values[i];
values[i]=temp;
}
}
}
案例细讲
例如: 7 5 6 1 3 2 8 0
首先记录最小元素的下标(某认为i即已经归为无需交换),然后在为排序的数组序列中找到最小的元素并且记录其下标。最后进行交换即可
第一次大循环结果:
0 5 6 1 3 2 8 7
第二次:
0 1 6 5 3 2 8 7
第三次
0 1 2 5 3 6 8 7
第四次
0 1 2 3 5 6 8 7
第五次
0 1 2 3 5 6 8 7
第六次
0 1 2 3 5 6 8 7
第七次
0 1 2 3 5 6 7 8
可见最后一个元素只有一种放法(即自动归位)
冒泡排序
冒泡排序利用:如果一个数组是无序的,它必然包含两个不符合排序规则的相邻元素。冒泡排序算法不断地检索数组,交换这样不合序的元素的位置,直到找不到需要交换的元素为止。
伪代码展示:
/*
* Bubblesort (Data:values[])
* //在数组完成排序前不断重复
* Boolean: not_sorted = True
* While(not_sorted)
* //假设我们没有找到需要交换的元素
* not_sorted = False
*
* //在数组中寻找不合序的相邻元素
* For i=0 To <len of values>-1
* //判断元素i与元素i-1是否合序
* If (values[i] < values[i-1]) Then
* //将他们交换
* Date : temp = values[i]
* values [i] = values[i-1]
* values[i-1] = temp
*
* //数组还没有排好序
* not_sorted = True
* End If
* Next i
* End While
*/
C语言代码实现:
#define True 1
#define Flase 0
void Bubblesort(int *values,int n)//冒泡排序1
{
_Bool not_sorted = True;
while(not_sorted)
{
not_sorted = Flase;
for(int i=0;i<n-1;i++)
{
if(values[i]>values[i+1])
{
int temp=values[i];
values[i]=values[i+1];
values[i+1]=temp;
not_sorted= True;
}
}
}
}
第二种版本(无判断有无排好序)
void Bubblesort(int *values,int n)//冒泡排序2
{
for ( int i = 0; i < n - 1; i++){
for (int j = 0; j < n - 1 - i; j++)
{
if (values[j] > values[j + 1])
{
int temp = values[j];
values[j] = values[j + 1];
values[j + 1] = temp;
}
}
}
以下为结合第一种和第二种的优点的优化冒泡
void Bubblesort(int *values,int n)//冒泡排序3
{
_Bool not_sorted = True;int n_i=n-1;
while(not_sorted)
{
not_sorted = Flase;
for(int i=0;i<n_i;i++)
{
if(values[i]>values[i+1])
{
int temp=values[i];
values[i]=values[i+1];
values[i+1]=temp;
not_sorted= True;
}
}--n_i;
}
}
案例详解
例如 0 1 2 4 5 6 3 7 8 9
该数组大部分元素已经合序。在第一次检索数组时,算法发现6和3不合序,交换位置。
0 1 2 4 5 3 6 7 8 9
第二次发现5和3不合序,交换位置
0 1 2 4 3 5 6 7 8 9
第三次交换不合序的3和4。
0 1 2 3 4 5 6 7 8 9
最后一次没发现不合序的元素,结束算法。
冒泡排序算法优化
1.通过案例发现有些元素有可能可以一次性移动多个单位到对应位置,就无需每次都交换数值,将其重新放入数组种去。
2.一般化情况,算法可以在遇到上一次检索时最后交换的元素时结束此次检索。
最终优化代码:
以下为冒泡排序的双向版本,效率更高!
void Bubblesort_Final(int* values,int NumItems)//最终优化,冒泡排序
{
int min = 0;
int max = NumItems - 1;
while (min < max)
{
int last_swap = min - 1;
int i = min + 1;
while (i <= max)
{
if (values[i - 1] > values[i])
{
int tmp = values[i - 1];
int j = i;
do
{
values[j - 1] = values[j];
j++;
if (j > max) break;
} while (values[j] < tmp);
values[j - 1] = tmp;
last_swap = j - 1;
i = j + 1;
}
else
{
i++;
}
}
max = last_swap - 1;
last_swap = max + 1;
i = max - 1;
while (i >= min)
{
if (values[i + 1] < values[i])
{
int tmp = values[i + 1];
int j = i;
do
{
values[j + 1] = values[j];
j--;
if (j < min) break;
} while (values[j] > tmp);
values[j + 1] = tmp;
last_swap = j + 1;
i = j - 1;
}
else
{
i--;
}
}
min = last_swap + 1;
}
}
具体说明可参考Wikipedia(维基百科):
https://en.wikipedia.org/wiki/Cocktail_shaker_sort
综合代码展示
#include <stdio.h>
#define Ntext 10
#define MIN 10
#define MAX 100000
#define True 1
#define Flase 0
void S_num(int *,int );
void P_num(int *,int );
void Insertionsort(int *,int);//插入排序
void Selectionsort(int *,int);//选择排序
void Bubblesort(int *,int);//冒泡排序
void Bubblesort_Final(int* values,int NumItems);//最终优化,冒泡排序
int count=0;//步骤数
//Sort (Date:values []);
int main() {
int a[MIN];int b[MAX];
S_num(a,Ntext);
//Insertionsort(a,Ntext);
//Selectionsort(a,Ntext);
//Bubblesort(a,Ntext);
Bubblesort_Final(a,Ntext);
P_num(a,Ntext);
printf("%d",count);
return 0;
}
void Insertionsort(int *values,int len)//插入排序
{
/*
* For i=0 To <len of values>-1
* //将元素i移动到数组中已排序部分的合适位置上
* <找到第一个位置j,满足j <i 且 values[j]> values[i]>
* <将项移动到位置j>
* Next i
*/
int j;
for(int i=1;i<len;i++)
{
int temp=values[i];
for( j=i;j>0&&values[j-1]>temp;j--)
values[j]=values[j-1];
values[j]=temp;
P_num(values,8);//观看过程
}
//7 5 6 1 3 2 8 0
//1 5 6 7 3 2 8 0
//1 5 6 7 2 8 0
// 3
//时间复杂度?
}
void Selectionsort(int *values,int n)//选择排序
{
/*
* For i=0 To <len of values>-1
* //找到下标为i的元素
* <找到数组中满足j>=i的所有位置j中最小项>
* <交换values[i]和values[j]>
* Next i
*/
for(int i=0;i<n-1;i++)
{
int min=i;
for(int j=i+1;j<n;j++)
if(values[j]<values[min])
min=j;
if(min != i)
{
int temp=values[min];
values[min]=values[i];
values[i]=temp;
}
P_num(values,8);//过程演示
}
//7 5 6 1 3 2 8 0
//0 1 2 8 7 3 6 5
//0 1 2 3 7 8 6 5
}
void Bubblesort(int *values,int n)//冒泡排序
{
//int count=0;//计数,查看循环次数
#if 0 //原始
for ( int i = 0; i < n - 1; i++){
for (int j = 0; j < n - 1 - i; j++)
{
if (values[j] > values[j + 1])
{
int temp = values[j];
values[j] = values[j + 1];
values[j + 1] = temp;
}
count ++;
}
}
//0 1 2 4 5 6 3 7 8 9
//0 1 2 4 5 3 6 7 8 9
//0 1 2 4 3 5 6 7 8 9
//0 1 2 3 4 5 6 7 8 9
#endif
/*
* Boolean: not_sorted = True
* While(not_sorted)
* //假设我们没有找到需要交换的元素
* not_sorted = False
* //在数组中寻找不合序的相邻元素
* For i=0 To <len of values>-1
* If (values[i] < values[i-1]) Then
* //将他们交换
* Date : temp = values[i]
* values [i] = values[i-1]
* values[i-1] = temp
*
* //数组还没有排好序
* not_sorted = True
* End If
* Next i
* End While
*/
#if 0// 优化 1
_Bool not_sorted = True;
while(not_sorted)
{
not_sorted = Flase;
for(int i=0;i<n-1;i++)
{
if(values[i]>values[i+1])
{
int temp=values[i];
values[i]=values[i+1];
values[i+1]=temp;
not_sorted= True;
}
count++;
P_num(values,Ntext);
}
}
//0 1 2 4 5 6 3 7 8 9
//0 1 2 7 4 5 6 3 8 9
#endif
#if 0 //原始优化 1.1
for ( int i = 0; i < n - 1; i++){
_Bool not_sorted=True;
for (int j = 0; j < n - 1 - i; j++)
{
if (values[j] > values[j + 1])
{
int temp = values[j];
values[j] = values[j + 1];
values[j + 1] = temp;
not_sorted=Flase;
}
count ++;
}
//not_sorted? (break) :NULL;
if(not_sorted)break;
}
//0 1 2 4 5 6 3 7 8 9
//0 1 2 4 5 3 6 7 8 9
//0 1 2 4 3 5 6 7 8 9
//0 1 2 3 4 5 6 7 8 9
#endif
#if 0 //优化3(false)
_Bool not_sorted = True;
while(not_sorted)
{
not_sorted = Flase;
for(int i=1;i<n-1;i++)
{
if(values[i]<values[i-1])
{
int temp=values[i-1];
_Bool sorted_=1;
for(int j=i;j<n-1;j++)
{
if(values[j]>temp)
{
values[i-1]=values[j-1];
values[j-1]=temp;
sorted_=0;
}
count++;
}
if(sorted_)
{
values[i]=values[i-1];
values[i-1]=temp;
}
not_sorted= True;
}
P_num(values,Ntext);
}
}
//0 1 2 4 5 6 3 7 8 9
//0 1 2 5 4 6 3 7 8 9
#endif
#if 0 //优化2
_Bool not_sorted = True;int n_i=n-1;
while(not_sorted)
{
_Bool last_sorted = Flase;
not_sorted = Flase;
for(int i=0;i<n_i;i++)
{
if(values[i]>values[i+1])
{
int temp=values[i];
values[i]=values[i+1];
values[i+1]=temp;
not_sorted= True;
//log i+1; Then False all i=i+1;
n_i=i+1;
}
count++;
//P_num(values,Ntext);
}
}
//0 1 2 4 5 6 3 7 8 9
//4 1 5 6 1 6 3 8 9 10
//6 1 8 2 9 4 3 7 5 0 False
#endif
#if 1 //优化2.1
_Bool not_sorted = True;int n_i=n-1;
while(not_sorted)
{
not_sorted = Flase;
for(int i=0;i<n_i;i++)
{
if(values[i]>values[i+1])
{
int temp=values[i];
values[i]=values[i+1];
values[i+1]=temp;
not_sorted= True;
}
count++;
//P_num(values,Ntext);
}--n_i;
}
//0 1 2 4 5 6 3 7 8 9
//4 1 5 6 1 6 3 8 9 10
//6 1 8 2 9 4 3 7 5 0
#endif
//printf("%d\n",count);
}
void Bubblesort_Final(int* values,int NumItems)//最终优化,冒泡排序
{
int min = 0;
int max = NumItems - 1;
while (min < max)
{
int last_swap = min - 1;
int i = min + 1;
while (i <= max)
{
if (values[i - 1] > values[i])
{
int tmp = values[i - 1];
int j = i;
do
{
values[j - 1] = values[j];
j++;count++;
if (j > max) break;
} while (values[j] < tmp);
values[j - 1] = tmp;
last_swap = j - 1;
i = j + 1;
}
else
{
i++;count++;
}
}
max = last_swap - 1;
last_swap = max + 1;
i = max - 1;
while (i >= min)
{
if (values[i + 1] < values[i])
{
int tmp = values[i + 1];
int j = i;
do
{
values[j + 1] = values[j];
j--;count++;
if (j < min) break;
} while (values[j] > tmp);
values[j + 1] = tmp;
last_swap = j + 1;
i = j - 1;
}
else
{
i--;count++;
}
}
min = last_swap + 1;
}
}
void S_num(int *values,int n)
{
for(int i=0;i<n;i++)
scanf("%d",values+i);
}
void P_num(int *values,int n)
{
for(int i=0;i<n;i++)
printf("%d",*(values+i));
printf("\n");
}