冒泡排序
void maopao_sort(int a[], int num)
{
for (int p = num - 1; p >= 0; p--)
{
int flag = 0;
for (int i = 0; i < p; i++)
{
if (a[i] < a[i + 1])
{
swap(a[i], a[i + 1]);
}
flag = 1;
}
if (flag == 0)
break; //全程无交换退出
}
} //从后往前遍历后面的比前面的小交换,或者从前向后便利将大的放在后面 O(n^2) 交换相近元素下界(n^2)
从后往前遍历后面的比前面的小交换,或者从前向后便利将大的放在后面 O(n^2) 交换相近元素下界(n^2)
插入排序
void insert_sort(int a[], int num)
{
for (int p = 1; p < num; p++)
{
int temp = a[p];
int location = 1;
for (int i = p; i > 0 && a[i - 1] > a[p]; i--)
{
a[i] = a[i - 1]; //向后移一个若移动a[p]已经改变
location = i - 1; //记录当前遍历的元素的位置
}
a[location] = temp;
}
}
//插入排序 顺序看数组中的每一个数 从第二个数开始与之前的数比较
//面的数大则向后错去报从小到达的顺序最后在将数放入 最快O(n) 最慢O(n^2) 上界(n^2)
//相对于冒泡排序而言不需要每次比较都交换位置 冒泡每一项都需要看但是插入排序若顺序正确那么只需比较最后一个
插入排序 顺序看数组中的每一个数 从第二个数开始与之前的数比较
前面的数大则向后移 从小到大的顺序最后在将数放入 最快O(n) 最慢O(n^2) 上界(n^2)
相对于冒泡排序而言不需要每次比较都交换位置 冒泡每一项都需要看但是插入排序若顺序正确那么只需比较最后一个
希尔排序
一串数字中的逆序对决定了交换次数而冒泡排序与插入排序相 同
思路 冒泡排序插入排序一次只能消灭一个逆序对,一次多消灭几个逆序对 不再相邻交换跳着交换
void shell_sort(int a[], int num)
{
for (int i = num / 2; i >= 1; i / 2)
{
for (int p = i; p < num; p++) //相当于每i个分为一组每个组都进行插入排序
{
int temp = a[p];
int location = p;
for (int j = p; j > 0 && a[j - i] > temp; j -= i) //每一项都和之前的比
{
a[j] = a[j - i];
location = j - i;
}
a[location] = temp;
}
}
}
// 希尔排序最外层是增量的循环内部是一个插入排序
//但是希尔排序最坏的情况下他的排序复杂度为增长速度真的是(n^2)
希尔排序最外层是增量的循环内部是一个插入排序但是希尔排序最坏的情况下他的排序复杂度为增长速度真的是(n^2)
堆排序
void selection_sort(int a[], int n)
{
//position=findmin();怎么找到最小元 堆排序
//swap(a[i],a[position])
}
//选择排序 每次选择未排序的最小元 将为排序部分的最小元换到已排序的最后部分
void PercDown(int A[], int p, int N)
{ /* 改编代码4.24的PercDown( MaxHeap H, int p ) */
/* 将N个元素的数组中以A[p]为根的子堆调整为最大堆 */
int Parent, Child;
int X;
X = A[p]; /* 取出根结点存放的值 */
for (Parent = p; (Parent * 2 + 1) < N; Parent = Child)
{
Child = Parent * 2 + 1;
if ((Child != N - 1) && (A[Child] < A[Child + 1]))
Child++; /* Child指向左右子结点的较大者 */
if (X >= A[Child])
break; /* 找到了合适位置 */
else /* 下滤X */
A[Parent] = A[Child];
}
A[Parent] = X;
} //每个分支确保父节点最大
void HeapSort(int A[], int N)
{ /* 堆排序 */
int i;
for (i = N / 2 - 1; i >= 0; i--) /*从后向前建立最大堆 */
PercDown(A, i, N);
for (i = N - 1; i > 0; i--)
{
/* 删除最大堆顶 */
swap(A[0], A[i]); /* 见代码7.1 */
PercDown(A, 0, i); //每次将最后堆的叶子节点与第一个最大的父元素交换位置
//再将剩下的元素重新进行堆排序
}
} // 复杂度nlogn
归并排序
//有序子列的归并 各序列每一项按顺序比较合并O(n) 递归分而治之的应用
void merge(int a[], int temp[], int l, int r, int rightend)
{
//将a[l]-a[r-1] 和 a[r]-a[rightend]合并为一个子序列
int leftend = r - 1; // 左边终点位置
int position = l; //合并序列的其起始下表为l
while (l <= leftend && r <= rightend)
{
if (a[l] <= a[r])
{
temp[position++] = a[l++];
}
/* 将左边元素复制到TmpA */
else
{
temp[position++] = a[r++];
}
/* 将右边元素复制到TmpA */
}
while (l <= leftend)
{
temp[position++] = a[l++];
}
while (r <=rightend)
{
temp[position++]= a[r++];
}
int NumElements = rightend;
for(int i = 0; i < NumElements; i++, rightend -- )
a[rightend] = temp[rightend]; /* 将有序的TmpA[]复制回A[] */
}
void merge_sort(int a[], int temp[], int left, int right)
{
int center;
if (left < right)
{
//将一个数列从左右拆分只有一个元素时停止拆分合并
center = (left + right) / 2;
merge_sort(a, temp, left, center);
merge_sort(a, temp, center, right);
merge(a, temp,left,center+1,right);
}
}
void MergeSort( int A[], int N )
{ /* 归并排序 */
int *TmpA;
TmpA = (int *)malloc(N*sizeof(int));
if ( TmpA != NULL ) {
merge_sort( A, TmpA, 0, N-1 );
free( TmpA );
}
else printf( "空间不足" );
}
快排
主元的选择 每次取头尾中间的三个数互换位置小大中 并将中间的元素放在序列的倒数第二个 两个指针分别从头和尾前进
按照最后元素进行比较交换进而能够确认所选主元的准确位置
//快速排序 O(nlogn) 主元的选择影响了快慢 选择主元取几个数的中位数
//相对插入排序而言快排每次插入的位置都是正确的不会再改变
void select_mid(int A[],int Left,int Right)
{
int Center = (Left+Right) / 2;
if ( A[Left] > A[Center] )
swap( A[Left], A[Center] );
if ( A[Left] > A[Right] )
swap( A[Left], A[Right] );
if ( A[Center] > A[Right] )
swap( A[Center], A[Right] );
/* 此时A[Left] <= A[Center] <= A[Right] */
swap( A[Center], A[Right-1] ); /* 将基准Pivot藏到右边*/
/* 只需要考虑A[Left+1] … A[Right-2] */
/* return A[Right-1]; 返回基准Pivot */
}
void Qsort( int A[], int Left, int Right )
{ /* 核心递归函数 */
int Pivot, Cutoff, Low, High;
if ( Cutoff <= Right-Left ) { /* 如果序列元素充分多,进入快排 */
Pivot = Median3( A, Left, Right ); /* 选基准 */
Low = Left; High = Right-1;
while (1) { /*将序列中比基准小的移到基准左边,大的移到右边*/
while ( A[++Low] < Pivot ) ;
while ( A[--High] > Pivot ) ;
if ( Low < High ) Swap( &A[Low], &A[High] );
else break;
}
Swap( &A[Low], &A[Right-1] ); /* 将基准换到正确的位置 */
Qsort( A, Left, Low-1 ); /* 递归解决左边 */
Qsort( A, Low+1, Right ); /* 递归解决右边 */
}
else{
//序列中元素少的时候可以考虑其他的排序方式
}
}
表排序
表排序的实现 n个数字排列会由若干个独立的环组成 见每个换对应位置放对
基数排序
基数排序之前的几种排序都是根据比较大小的方法来进行排序最快nlogn
桶排序 开足够大的数组 每一个元素对应值放进数组的对应下标之中
基数排序 此为优先原则 对应n个数 每一个数按照位数从低到高进行排序
基数排序 - 次位优先
/*
假设元素最多有MaxDigit个关键字,基数全是同样的Radix */
#define MaxDigit 4
#define Radix 10
/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node {
int key;
PtrToNode next;
};
/* 桶头结点 */
struct HeadNode {
PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
int GetDigit ( int X, int D )
{ /* 默认次位D=1, 主位D<=MaxDigit */
int d, i;
for (i=1; i<=D; i++) {
d = X % Radix;
X /= Radix;
}
return d;
}
void LSDRadixSort( ElementType A[], int N )
{ /* 基数排序 - 次位优先 */
int D, Di, i;
Bucket B;
PtrToNode tmp, p, List = NULL;
for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */
B[i].head = B[i].tail = NULL;
for (i=0; i<N; i++) { /* 将原始序列逆序存入初始链表List */
tmp = (PtrToNode)malloc(sizeof(struct Node));
tmp->key = A[i];
tmp->next = List;
List = tmp;
}
/* 下面开始排序 */
for (D=1; D<=MaxDigit; D++) { /* 对数据的每一位循环处理 */
/* 下面是分配的过程 */
p = List;
while (p) {
Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */
/* 从List中摘除 */
tmp = p; p = p->next;
/* 插入B[Di]号桶尾 */
tmp->next = NULL;
if (B[Di].head == NULL)
B[Di].head = B[Di].tail = tmp;
else {
B[Di].tail->next = tmp;
B[Di].tail = tmp;
}
}
/* 下面是收集的过程 */
List = NULL;
for (Di=Radix-1; Di>=0; Di--) { /* 将每个桶的元素顺序收集入List */
if (B[Di].head) { /* 如果桶不为空 */
/* 整桶插入List表头 */
B[Di].tail->next = List;
List = B[Di].head;
B[Di].head = B[Di].tail = NULL; /* 清空桶 */
}
}
}
/* 将List倒入A[]并释放空间 */
for (i=0; i<N; i++) {
tmp = List;
List = List->next;
A[i] = tmp->key;
free(tmp);
}
}
swap函数实现
void swap1(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
void swap2(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void swap3(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}