冒泡排序法
从低到高慢慢扩大已排序部分。找到未排序部分的第一个位置,然后从数组末尾开始依次比较相邻两个元素,如果大小关系相反则交换位置。这样可以保证每次都把最小的那个换到最前面。如果某一次没有元素交换,则表示排序完成。
例题:Bubble Sort
- 输入n和数组,输出排序后的数组和交换次数。
交换次数即逆序数
int exchange = 0; //交换次数
bool flag = true; //判断是否已经排好序
int index = 0; //表示未排序部分的最小值
while (flag && index < n)
{
flag = false;
for (int j = n - 1; j >= index + 1; j--)
if (a[j - 1] > a[j])
{
swap(a[j - 1], a[j]);
exchange ++;
flag = true;
}
index++; //每一次循环结束表示确定了一个min
}
插入排序法
如果只有1个数就是已经排好序的,所以从第2个开始确定这个数应该插入到已排好序的数组的哪个位置。1. 取出未排序部分的开头元素赋给v。2. 在已排序部分,将所有比v大的元素向后移动一个单位。3. 将已取出的元素v插入空位。
例题:Insertion Sort
for (int i = 1; i < n; i++) //从第2个元素开始插入已排序部分
{
int key = a[i];
int j;
for (j = i - 1; j >= 0 && key < a[j]; j--) //不符合条件的情况j == -1或是key >= a[j]
a[j + 1] = a[j];
a[j + 1] = key; //注意这里是j + 1
//Print(n);
}
- 优化:在已排序数组中找到该数的插入位置可以采用二分算法
选择排序法
从坐标0开始,每次找出最小的那个元素去替换未排序的开始元素。
例题:Selection Sort
int exchange = 0;
for (int i = 0; i < n - 1; i++)
{
int minj = i;
for (int j = i; j < n; j++)
if (a[j] < a[minj])
minj = j; //找到值最小的元素
swap(a[minj], a[i]);
if (i != minj)
exchange++;
}
归并排序法
以整个数组为对象执行 mergeSort m e r g e S o r t :
1.将给定的包含 n n 个元素的局部数据“分割”成两个局部数组,每个数组各包含个元素。 (Divide) ( D i v i d e )
2.对两个局部数组分别实行 mergeSort m e r g e S o r t 排序。 (Solve) ( S o l v e )
3.通过 merge m e r g e 将两个已排序完毕的局部数组“整合”成一个数组。 (Conquer) ( C o n q u e r )
例题:Merge Sort
void merge(int left, int mid, int right)
{
int x = mid - left;
int y = right - mid;
for (int i = 0; i < x; i++)
L[i] = a[left + i];
for (int i = 0; i < y; i++)
R[i] = a[mid + i];
L[x] = R[y] = MAX;
int i = 0, j = 0;
for (int k = left; k < right; k++)
{
if (L[i] <= R[j])
a[k] = L[i++];
else
a[k]=R[j++]
}
}
void MergeSort(int left, int right)
{
if (left + 1 < right)
{
int mid = (left + right) >> 1;
MergeSort(left, mid);
MergeSort(mid, right);
merge(left, mid, right);
}
}
快速排序法
以整个数组为对象执行 quickSort q u i c k S o r t
1. 通过分割将对象局部数组分割为前后两个局部数组。 (Divide) ( D i v i d e )
2. 对前半部分的局部数组执行 quickSort q u i c k S o r t 。 (Solve) ( S o l v e )
3. 对后半部分的局部数组执行 quickSort q u i c k S o r t 。 (Solve) ( S o l v e )
例题:Quick Sort
int partition(int left, int right)
{
Card x = a[right];
int i = left - 1;
for (int j = left; j < right; j++)
{
if (a[j].val <= x.val)
{
i++;
swap (a[i], a[j]);
}
}
swap(a[i+1], a[right]);
return i + 1;
}
void quickSort(int left, int right)
{
int selected;
if (left < right)
{
selected = partition(left, right);
quickSort(left, selected - 1);
quickSort(selected + 1, right);
}
}
如何证明快速排序是稳定的还是不稳定的?
- 用 id i d 标记,和 mergeSort m e r g e S o r t 的结果相对比。
排序方法 | 平均时间 | 最坏情况 | 最好情况 | 辅助空间 | 稳定性 |
---|---|---|---|---|---|
插入排序 | O(n2) O ( n 2 ) | O(n2) O ( n 2 ) | O(n) O ( n ) | O(1) O ( 1 ) | false f a l s e |
选择排序 | O(n2) O ( n 2 ) | O(n2) O ( n 2 ) | O(n2) O ( n 2 ) | O(1) O ( 1 ) | true t r u e |
冒泡排序 | O(n2) O ( n 2 ) | O(n2) O ( n 2 ) | O(n) O ( n ) | O(1) O ( 1 ) | true t r u e |
归并排序 | O(nlogn) O ( n l o g n ) | O(nlogn) O ( n l o g n ) | O(nlogn) O ( n l o g n ) | O(n) O ( n ) | true t r u e |
快速排序 | O(nlogn) O ( n l o g n ) | O(n2) O ( n 2 ) | O(nlogn) O ( n l o g n ) | O(logn) O ( l o g n ) | false f a l s e |