1、冒泡排序
C 程序如下:
// 冒泡排序
void sort2(int a[], int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1- i ; j++)
{
if (a[j] > a[j + 1])
{
swap(a[j], a[j + 1]);
}
}
}
}
复杂度分析:空间复杂度为 O(1),最坏时间复杂度为 O(n^2),最好情况下时间复杂度为 O(n).平均时间复杂度为 O(n^2)。冒泡排序显然是一种稳定的排序方法。
2、快速排序
快速排序是冒泡排序的一种改进。它的基本思想是基于分治法的:在待排序表 L[1.....n] 中任取一个元素 pivot 作为基准通过一趟排序,将 L 分成两个部分L[1......k-1] 和 L[k+1...n],使得L[1......k-1] 中的所有元素都小于等于 pivot, L[k+1...n] 都大于 pivot 。最终,pivot 就放在了 L(k) 的位置。这个过程称为一趟快速排序。然后,递归地对两个子表重复上述过程,直到每部分只有一个元素或者为空。此时,所有的元素都放在了应该放的位置。
假设划分算法已知,为partition(),那么,递归调用算法为:
void QuickSort(int A[], int low, int high)
{
if (low < high)
{
int pivotpos = Partition(A,low,high);
QuickSort(A,low,pivotpos - 1);
QuickSort(A,pivotpos +1,high);
}
}
而最难的划分算法
1)第一种思路:两个下标分别从首、尾向中间扫描
此种方法,表中的第一个元素作为基准元素 pivot ,则表中比 pivot 大的向右移动,比 pivot 小的向左移动
C 程序如下:
//快速排序
int Partition(int A[], int low, int high)
{
int pivotpos = A[low]; // 当前表的第一个元素作为基准值
while (low < high) // 循环跳出的条件
{
while (low < high && A[high] > pivotpos) // 比基准值小的元素往左移动
--high;
A[low] = A[high];
while (low < high && A[low] < pivotpos) // 比基准值大的往右移动
++low;
A[high] = A[low];
}
A[low] = pivotpos; // 基准值最终存放的位置
return low; // 返回基准位置
}
void QuickSort(int A[], int low, int high)
{
if (low < high)
{
int pivotpos = Partition(A,low,high);
QuickSort(A,low,pivotpos - 1);
QuickSort(A,pivotpos +1,high);
}
}
int main()
{
int a[] = { 1, 3, 5, 7,12,0,56,4, 2 ,6};
int len = (int)sizeof(a) / sizeof(*a);
//sort2(a,len);
QuickSort(a, 0, len -1);
for (int i = 0; i < len; i++)
cout << a[i] << endl;
return 0;
}
举个例子,
待排序列 | 3 | 8 | 7 | 1 | 2 | 5 | 6 | 4 |
第1次 | 2 | 8 | 7 | 1 | 5 | 6 | 4 | |
第2次 | 2 | 7 | 1 | 8 | 5 | 6 | 4 | |
第3次 | 2 | 1 | 7 | 8 | 5 | 6 | 4 | |
第4次 | 2 | 1 | 7 | 8 | 5 | 6 | 4 | |
第5次 | 2 | 1 | 3 | 7 | 8 | 5 | 6 | 4 |
一个萝卜一个坑,第一次,将‘2’挖出,放到原来 ‘3’那个坑里面。2 那个坑就需要 8 去补。。。依次类推,最后,基准元素 3 就被放到了第 三 个位置。
(2)第二种思路:两个指针一前一后逐步向后扫描
C 代码
int partition2(int a[], int p, int r)
{
int x = a[r]; // 选择最后一个元素作为基准
int i = p - 1; // i 初始值是第一个元素的之前的位置。i 一直指向的是比基准元素小的那个值
for (int j = p; j < r; j++) // j 从第一个元素开始往后遍历
{
if (a[j] <= x)
{
++i; // 如果有比基准小的,就将 i 向后移动一个,代表元素个数
swap(a[i],a[j]);
}
}
swap(a[i + 1], a[r]);
return (i + 1);
}
void QuickSort(int A[], int low, int high)
{
if (low < high)
{
//int pivotpos = Partition(A,low,high);
int pivotpos = partition2(A, low, high);
QuickSort(A,low,pivotpos - 1);
QuickSort(A,pivotpos +1,high);
}
}
int main()
{
int a[] = {1,3,4,2,67,45,21};
QuickSort(a,0,6);
for (int i = 0; i < 7; i++)
{
cout << a[i] << endl;;
}
return 0;
}
复杂度分析:
1、2013 腾讯
题目描述:一个数组中存储有且仅有大写和小写字母,编写一盒函数对数组内的字母重新排列,让小写字母在大写字母之前;
分析:可以使用快速排序的一次快排
bool isupper(char c)
{
if (c >= 'A' && c <= 'Z')
return true;
return false;
}
bool islower(char c)
{
if (c >= 'a' && c <= 'z')
return true;
return false;
}
void partition(char str[], int low, int high)
{
while (low < high)
{
while (low < high && isupper(str[high]))
--high;
while (low < high && islower(str[low]))
++low;
char c_temp = str[high];
str[high] = str[low];
str[low] = c_temp;
}
}
int main()
{
char str[] = {'a','A','Z','d','B','s','b'};
partition(str,0,6);
cout << str;
return 0;
}
一些说明:形参可以使用 string 类型,但是需要利用引用 & 类型,如:
void partition(string str, int low, int high)
2、