冒泡排序思想:通过两个循环对元素进行比较,并调换位置,每一趟小循环都会产生一个最大值/最小值放到最后面,然后每个小循环只对小于第一次循环的个数进行操作。
第一步:首先看一下遍历操作,打印10*10的星号
int main()
{
for (int i = 0; i < 10 ; i++)
{
for(int j = 0 ;j < 10;j++)
{
printf("*");
}
printf("\n");
}
}
第二步:从1开始,打印到10个星号
循环体更改为:
for (int i = 0; i < 10 ; i++)
{
for(int j = 0 ;j < 10 - i - 1 ;j++)
{
printf("*");
}
printf("\n");
}
普通循环体冒泡排序:
第三步:打印出数组指向对象
int main()
{
int a[] = {55,88,44,6,64,11,2};
for(int i=0;i<sizeof(a)/sizeof(int);i++)
{
for(int j=0;j<end(a)-begin(a)-i;j++)
{
cout << a[j] << " ";
}
cout << endl;
}
}
按照从小到大排序的顺序,每一次小循环将最大的数值排列到最后。
这里注意第二个循环的判断条件应为:
j<end(a)-begin(a)-i-1;
因为后面还需要进行判断操作,上面只是打印出每次小循环获得的数好理解。
第四步:冒泡排序代码
int main()
{
int a[] = {55,88,44,6,64,11,2};
for(int i=0;i<sizeof(a)/sizeof(int);i++)
{
for(int j=0;j<end(a)-begin(a)-i-1;j++)
{
if (a[j]>a[j+1])
{
int temp;
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
}
}
}
for (int i = 0;i<sizeof(a)/sizeof(int);i++)
{cout << a[i] << " ";}
}
第五步:下面写一下指针版本的冒泡排序
int main()
{
int a[] = {55,88,44,6,64,11,2};
int* p;
p = a;
for(int i = 0; i < end(a)-begin(a) ; i++)
{
for(int j = 0 ; j < end(a)-begin(a) - i - 1 ; j++)
{
if(*(p+j)>*(p+j+1)) //判断相邻元素的大小
{
int k = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = k; //借助中间变量进行值传递
}
}
}
for(int i = 0;i<sizeof(a)/sizeof(int);i++)
{cout << a[i] << " ";}
}
奇怪,不懂C++为什么有时候会报一些神奇的错误:
tempCodeRunnerFile.cpp:1:5: error: expected unqualified-id before 'for'
1 | for (int i = 0; i < end(a)-begin(a) ; i++ )
| ^~~
tempCodeRunnerFile.cpp:1:21: error: 'i' does not name a type
1 | for (int i = 0; i < end(a)-begin(a) ; i++ )
| ^
tempCodeRunnerFile.cpp:1:43: error: 'i' does not name a type
1 | for (int i = 0; i < end(a)-begin(a) ; i++ )
| ^
tempCodeRunnerFile.cpp:13:5: error: expected unqualified-id before 'for'
13 | for (int i = 0;i<sizeof(a)/sizeof(int);i++)
| ^~~
tempCodeRunnerFile.cpp:13:20: error: 'i' does not name a type
13 | for (int i = 0;i<sizeof(a)/sizeof(int);i++)
| ^
tempCodeRunnerFile.cpp:13:44: error: 'i' does not name a type
13 | for (int i = 0;i<sizeof(a)/sizeof(int);i++)
| ^
[Done] exited with code=1 in 0.271 seconds
这个错误在重新输入代码和调整下位置之后又消失了,推测可能是因为对内存操作了的原因。
时间复杂度:
最优情况在于所有元素都是排列好顺序的,那么不需要进行更换的三个步骤,因此时间复杂度是遍历的时间,则为1+2+3…+(n-1) = [ n(n-1) ] / 2,所以最优时间复杂度为O(n2)。
同时也可以在代码中添加优化,使得时间复杂度为O(n),因为排序好的元素不需要比较,设置一个flag对每个元素进行判断,因此遍历可以得到O(n)的结果,但这个对结果影响不大,平均时间复杂度还是O(n2)。
int main()
{
int a[] = {55,88,44,6,64,11,2};
bool flag;
flag = false;
for(int i=0;i<sizeof(a)/sizeof(int);i++)
{
for(int j=0;j<end(a)-begin(a)-i-1;j++)
{
if (a[j]>a[j+1])
{
int temp;
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
flag = true;
}
}
if(flag == false)
return;
}
for (int i = 0;i<sizeof(a)/sizeof(int);i++)
{cout << a[i] << " ";}
}
最坏情况是所有元素逆序排序,因此要做上述代码中更换元素的三个步骤,所以为3*[ n(n-1) ] / 2,为[ 3n(n-1) ] / 2,最坏时间复杂度也为O(n2)。
因此平均时间复杂度为O(n2)。
空间复杂度:交换变量时临时占据的空间大小
最优空间复杂度为所有元素排序正确,不需要临时存储,为0;
最差空间复杂度为所有元素逆序排序,每个元素都需要一个存储空间,则空间复杂度为O(n);
平均空间复杂度为O(1)。