1. 交换两个数————位运算
static void swap(int *pa, int *pb)
{
*pa ^= *pb;
*pb ^= *pa;
*pa ^= *pb;
return;
}
2. 简单选择排序
1. What:
- 每一趟在无序区选择一个最小的元素。
- 把所选中的无序区中的元素放到有序区中的最终位置上。
- 算法效率与初始数据的顺序性无关,因为当序列为正序时不会减少比较的次数。
2.How:
static void selectSort(int a[], int n)
{
int i = 0;
int j = 0;
int Min = 0;
for (i = 0; i < n-1; i++) /* n 个数需要 n-1 的选择 */
{
Min = i;
for (j = i+1; j < n; j++) /* 从无序区中选择出最小的元素 */
{
if (a[Min] > a[j])
{
Min = j; /* 保存在无序区中的最小元素的下标 */
}
}
if (Min != i)
{
swap(&a[Min], &a[i]);
}
}
return;
}
3.Why:
- 每一趟排序使得一个元素归位,有序区的元素一定小于(顺序)[大于(逆序)]无序区的元素,因此是全局有序的。
- Min 用来保存无序区最小元素 的下标。
- 算法的效率与初始数据的状态无关(无论逆序还是正序,比较次数都不会减少)。
3. 堆排序
1. What:
- 是简单选择排序的改进
- 初始建堆 ,a[0] 为哨兵,待排序元素存储在 a[1,n] 中
- 将 a[1, n] 调整为堆,交换 a[1] 和 a[k] (k = n n-1 ... 2)
2.How:
/* 1. 完全二叉树调整为大根堆的算法 */
static void shiftHeap (int a[], int low, int high)
{
int i = low;
int j = 2*i; /* a[j] 是 a[i] 的左孩子 */
a[0] = a[i]; /* a[0] 临时备份数据*/
while (j <= high)
{
/* j 指向较大的孩子 */
if (j<high && a[j+1]>a[j]) /* 保证 j+1 有意义 */
{
j++;
}
if (a[j] > a[0]) /* 孩子结点大于父节点,需要调整 */
{
a[i] = a[j];
i = j;
j = 2*i;
}
else
{
break;
}
}
a[i] = a[0]; /* 被筛选的节点放入最终的位置 */
}
static void heapSort (int a[], int n)
{
int i = 0;
for (i=n>>1; i>=1; i--) /* 初始建立大根堆 */
{
shiftHeap(a,i,n);
}
for (i=n; i>=2; i--) /* 每一趟将无序区中一个最大的元素归位,需要 n-1 趟 */
{
swap(&a[1],&a[i]);
shiftHeap(a,1,i-1);
}
}
3.Why:
- 每一趟排序使得一个元素归位,是全局有序
- 是一个在顺序表中的完全二叉树
- 大根堆(不小于孩子节点) 小根堆(不大于孩子节点)