声明,学习排序过程参考了极客学院视频教程,链接如下。
http://www.jikexueyuan.com/course/2542.html
分析问题解决问题的部分为原创。
每个排序都有不同应用场景。
红色,问题;
蓝色,技术要点;
绿色,完成结果,其他。
(一)冒泡法,插入,快速
(1)冒泡排序,乱序 到 顺序。
问题00:时间复杂度,稳定否?最差O(n^2);
方法:看做气泡,大气泡向上跑。每遍历一次,最大值排到最前边。结果: 由大到小排序。
头文件,iosstream,vector,没有.h
函数体,(大到小)
void Bulldle2(int *array , int num) //函数声明格式问题1;
void Bulldle(int * array, int num)//数组指针,元素个数。遍历次数num-1
{
int i,j,temp;
for(i=0;i<num-1;i++)
{
for (j=i+1;j<num;j++)
if(array[i]<array[j])
{
temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}
}
int main()
{
int array[]={7,5,3,9,1,3};//数组赋值方法,注意5
Bulldle(array,6);//传递参数格式,注意6
int i;
for(i=0;i<sizeof(array)/sizeof(int);i++)
cout<<array[i]<<endl;//cout,endl问题2;std::cout<<array[i]<<std::endl;//环境Xcode Mac
return 0;
}
//[优化1] 若后面元素已经置位,则不需要进一步排序。
void Bulldle2(int *array , int num)
{
int i,j,temp;
int flag=1;
for(i=0;i<num-1&&flag;i++)
{
flag=0;
for(j=i+1;j<num;j++)
if(array[i]>array[j])//小于号还是大于号,直接决定了,从小到大还是从大到小,i代表前面一个,j代表后面一个,前大于后交换,则从小到大,反之,从大到小。
{
temp=array[i];
array[i]=array[j];
array[j]=temp;
flag=1; //flag 意义,每次i外循环,循环所有数据,当不发生交换时,意味着后面的全部满足从小到大,也就不需要进行下一次循环了。
}
}
}
问题00:时间复杂度,稳定否?最差O(n^2);
【答】
使用.c,endl报错;原因是cpp文件。
问题0:C与cpp区别?
【答】
另外,c中无iosstream。【是iostream,打错】。
问题1:函数声明方法,最后有无分号?
【答】
问题2:cout,警告,程序建议修改为std::cout;endl,同理。std代表什么。注意箭头朝向cout。
【答】
注意3:for(a,b,c)里面习惯性写了逗号,应该是分号。(受Matlab影响)
注意4:头文件中,#include <iostream> #include <vector>, 并没有.h
注意5:int array[]={7,5,3,9,1,3};//数组赋值方法,不带指针符号,传递函数两个,第一个*array就代表数组第一个元素,第二个代表数组长度。
大括号{1,2,3}形式。
注意6:传递参数格式。
X注意7:数组中有12个整数的时候,会报错。原因,中文输入法逗号。55555555TAT
修改后,成功排序。
(2)插入排序
问题:思想,时间复杂度,稳定性
思想:已排序好的序列,插入一个外来的元素。
实现:
c++
头文件,iostream,using namespace std;//何意
void InsertSort(int *array,int n)
{
int i,j;
int temp;
//从第二个元素开始进行插入操作,为其在前面排序好的序列中找到位置
for(i=1;i<n;i++)
temp=array[i];
for(j=i-1;j>=0;j--) //for循环解释,外循环从i=第2个元素开始,j遍历已排序好的倒序,找到第一个比array[i]小的,把array[i]放在此值之后。
{
if(array[j]>temp) //所有大于temp值的,向后移一位,腾出空间。继续比较。
array[j+1]=array[j];
else
break;
}
//插入合适位置
array[j+1]=temp;//擅自增加的大括号{},之前位置加错,导致无法正常排序。
//另外,注意这里是把temp的值赋给小值之后的位置,而不是array[i],因为array[i]已经被array[i-1]占据,它已不再是原来的配方啦~
for(i=0;i<n;i++)
cout<<array[i]<<endl;
}
int main()
{
int array[]={5,4,7,8,9};
int n=sizeof()/sizeof(int);
InsertSort(array,n);//忘了加两个分号= =
}
问题1:using namespace std;//何意
---------------------------------------------------------------------------20160605未完待续--------------------------------------------------------------------------------------------------------------------------------------
(3)快速排序
思想,时间复杂度
总体思想都是相似的:
(1)确立基准值,比基准值小的部分,放在左边,比基准值大的部分放在右边;确定基准值的新位置;
(2)以新位置为界,左边组成子序列1,头-基准值位置;右边组成子序列2,基准值位置-尾;
(3)子序列按照相同思想排序。
(4)结束条件,头尾相等,或者说,头>尾。
假设有一个元素可以将整个数组,分成两个子数组,前面小于基准点,后面大于基准点。
递归调用。一直递归,直至某个子数组<=1个元素。
a)基准点概念;b)递归调用
字符串处理过程中使用过,基准点概念。
c语言实现1
#include <stdio.h>
#include<stdlib.h>
第一种分割方法----------------------------------------------------------------------------------------------
//int partition(int *array,int left, int right) //本例子第一轮中,left=array[0]=9;right=array[8]=6;
//{
// int key=array[right]; //以最后一个元素为基准点,6
// int i=left-1; //i=0-1=-1;
// int temp;
// //开始以基准点为标准分割序列,j遍历的当前元素,i小于当前点的最后一个元素《字符串处理课程》
// for(int j=left;j<right;j++) //j=0,0<8.
// {
// if(array[j]<key) //array[0]=9>6,不满足小于号条件,则不执行花括号内容,j=j+1=1;array[1]=4<6,执行花括号内容;j=2,5<6;j=4,1<6
// {
// i++; //i=-1+1=0,互换i,j值;{4,9,5,2,1,3,7,8,6};{4,5,2,1,3,9,7,8,6};i=4
//
// temp=array[j];
// array[j]=array[i];
// array[i]=temp;
// }
// }
// //将基准点放在合适的位置 //把基准值6,放在第6位,array[4+1],{4,5,2,1,3,6,9,7,8}
// temp=array[i+1];
// array[i+1]=array[right];
// array[right]=temp;
// return i+1; //返回基准点所在位置的下标
//
//}
//
//第二种分割方法---------------------------------------------------------------------------------------------------------------------------------------------
//交换函数
void swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
}
//分割函数
int partition(int *array,int low,int high)
{
int key=array[low];
while(low<high)
{
//从后面找到一个合适的值和前面交换,
while(low<high&&array[high]>=key)
high--;
swap(&array[low],&array[high]);
while(low<high&&array[low]<=key)
++low;
swap(&array[low],&array[high]);
}
return low;
}
//递归过程1---------------------------------------------------------------------------------------------------------------------------------------------
void quicksort(int *array,int left,int right)
{
if(left<right)
{
int k=partition(array,left,right);
quicksort(array,left,k-1); //基准值3,前半部分{2,1,3,4,5};基准值1,{1,2,3,4,5}
quicksort(array,k+1,right); //基准值8,后半部分{7,8,9};;基准值9,{7,8,9};k=8,k+1=9,left(9)>right(8)递归结束
}
}
//第二种快速排序方法---------------------------------------------------------------------------------------------------------------------------------------------
//void quicksort2(int *array,int left,int right)
//{
// int i,j,key;
// if(left<right)
// {
// i=left; //按如下实例,i=0,j=12,k=array[0]=9;
// j=right;
// key=array[i]; //以最左边的元素作为分割基准点
// do{
// while(array[j]>key && i<j) //以下进入嵌套循环,第一层,判断ij不等,第二层循环第一个,如果右边的数比基准值大,且i<j,则不动,j--;
// j--; //从右向左找第一个小于基准值的位置j
// if(i<j) //找到了位置j //直到在右边找到第一个,比基准值小的数字,就把[j]值给[i],i++;
// {
// array[i]=array[j];
// i++;
// } //将第j个元素置于左端并重置i
// while(array[i]<key&&i<j) //问题,一个是大于号,一个是小于号啦。代表小数左移,大数右移。
///第二层循环第二个,如果左边的数比基准值小,且i<j,则不动,j++;
//
// i++; //从左向右找第一个大于标准的位置i
// if(i<j) //直到在左边找到第一个,比基准值大的数字,就把[i]值给[j],j--;
// {
// array[j]=array[i];
// j--;
// }
// } //将第i个元素置于右端并重置j
// while(i!=j);
// array[i]=key;
// quicksort2(array,left,i-1);
// quicksort2(array,i+1,right);
// }
//}
//按照第2种快速排序方法。比基准值小的,去左边,比基准值大的,去右边;定位基准值;头-基准值位置,为第一子序列;基准值位置-尾,为第二子序列。
//
//
//建议复习字符串处理课程。
int main()
{
int array[]={6,4,5,2,1,3,7};
int n=0;
n=sizeof(array)/sizeof(int);
quicksort(array,0,n);
int i;
for(i=0;i<n;i++)
printf("%d\n",array[i]);
return0;
}