# 排序算法

（1）算法思想（以升序举例）：

（2）代码实现

``````//O(N)最好顺序-O(N*N)最坏逆序
void insert_sort(int*a, int n)
{
for (int i = 0; i < n-1; ++i)
{
int end = i;
int x = a[i+1];
while (end >= 0)
{
if (a[end] > x)
{
a[end+1] = a[end];
--end;
}
else
{
break;
}
}
a[end + 1] = x;
}
}``````

（3）改进：希尔排序

``````//gap越小，越接近有序。pow(n,1.3)
void shell_sort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap/3 + 1;//gap>1都是预排序，gap==1为直接插入排序
for (int i = 0; i < gap; ++i)
{
for (int j = i; j < n - gap; j += gap)
{
int end = j;
int x = a[end + gap];
while (end >= 0)
{
if (a[end] > x)
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = x;
}
}
}
}``````

``````//O(N*N)
void select_sort(int* a, int n)
{
//assert(a);

int begin = 0, end = n - 1;
while (begin < end)
{
int min_ = begin, max_ = end;
for (int i = begin; i <= end; ++i)
{
if (a[i] < a[min_])min_ = i;
if (a[i] > a[max_])max_ = i;
}
swap(&a[begin], &a[min_]);
if (max_ == begin)
{
max_ = min_;
}
swap(&a[end], &a[max_]);
++begin;
--end;
}
}``````

``````//nlogn
void heap_sort(int* a, int n)
{
for (int i = (n - 2) / 2; i >= 0; --i)
{
heap_down(a, n, i);
}
int end = n - 1;
while (end > 0)
{
swap(&a[0], &a[end]);
heap_down(a, end, 0);
--end;
}
}``````

``````//O(n*n) 最好:n,遍历一次就知道结果
void bubble_sort(int* a, int n)
{
for (int i = 0; i < n; ++i)
{
int f = 0;
for (int j = 0; j < n-i-1; ++j)
{
if (a[j] > a[j+1])
{
f = 1;
swap(&a[j], &a[j+1]);
}
}
if (f == 0)
{
break;
}
}
}``````

(1)思想：每次排序找一个key，经过排序使得序列的左边数据都<=key，右边数据都>=key，递归处理。

``````void quick_sort(int* a, int begin, int end)
{
if (begin >= end)
return;
int keyi = quick1_sort(a, begin, end);
quick1_sort(a + begin, begin, keyi - 1);
quick1_sort(a + begin, keyi + 1, end);
}
//传统写法：选择一个key，右边先走，左边再走，交换，直到l==r
int quick1_sort(int* a, int begin, int end)
{
int l = begin;
int r = end;
int keyi = a[l];
while (l < r)
{
//右边先走
while (l < r && a[r] >= a[keyi])
{
r--;
}
//现在的a[r]<key
while (l < r && a[l] <= a[keyi])
{
l++;
}
swap(&a[l], &a[r]);
}
swap(&a[keyi], &a[l]);
keyi = l;
return keyi;
}
//挖坑法
int quick2_sort(int* a, int begin, int end)
{
int l = begin;
int r = end;
int key = a[begin];
int pit = begin;
while (l < r)
{
//右边先走
while (l < r && a[r] >= key)
{
r--;
}
a[pit] = a[r];
pit = r;//这是新的坑
while (l < r && a[l] <= key)
{
l++;
}
a[pit] = a[l];
pit = l;//这是新的坑
}
a[pit] = key;
return pit;
}
//前后指针法
int quick3_sort(int*a, int begin, int end)
{
int keyi = begin;
int prev = begin;
int cur = begin + 1;
while (cur <= end)
{
if (a[cur] < a[keyi])
{
++prev;
if(prev != cur)
swap(&a[prev], &a[cur]);
}
cur++;
}
swap(&a[prev], &a[keyi]);
return prev;
}``````

r一直往左边走，直到遇到l，说明这个位置右边的值都比Key大，相遇的位置是l上一轮停下来的，这里要么是key（第一轮），要么比key小（不是第一轮了，上一轮r换过去的），时间复杂度为nlogn。

(2)优化

``````//优化1=key每次都是最小或者最大效果最差：有序或者接近有序->1.随机选Key 2.三数选中
int get_key(int* a, int begin, int end)//得到下标
{
int mid = (begin + end) / 2;
if (a[begin] < a[mid])
{
if (a[mid] < a[end])return mid;
else if (a[begin] < a[end])return end;
else return begin;
}
else
{
if (a[end] > a[begin])return begin;
else if (a[mid] < a[end])return end;
else return mid;
}
}``````

``````void quick_sort(int* a, int begin, int end)
{
if (begin >= end)return;

if (end - begin > 10)//80%
{
int keyi = quick1_sort(a, begin, end);
quick1_sort(a + begin, begin, keyi - 1);
quick1_sort(a + begin, keyi + 1, end);
}
else
{
insert_sort(a,end -begin+1 );
}
}``````

(3)快拍的非递归写法

``````void quick_sort_nor(int* a, int begin, int end)
{
stack<int>st;
st.push(end);
st.push(begin);
while ()
{
int l = st.top();
st.pop();
int r = st.top();
st.pop();
//(l,key-i-1)(keyi+1,r)
int keyi = quick1_sort(a, l, r);
if (r > keyi + 1)
{
st.push(r);
st.push(keyi + 1);
}
if (l < keyi - 1)
{
st.push(keyi - 1);
st.push(l);
}
}
}``````

（1）思想：先把序列递归分成小区间，再把小区间排成有序，接着把已经有序的小区间进一步变成有序的区间。

``````void merge_sort(int* a, int n)
{
int* temp = (int*)malloc(sizeof(int) * n);
if (temp == NULL)
{
exit(-1);
}
_merge_sort(a, 0, n - 1, temp);
free(temp);
}
void _merge_sort(int* a, int begin, int end, int* temp)
{
if (begin >= end)return;

int mid = (begin + end) / 2;
_merge_sort(a, begin, mid, temp);
_merge_sort(a, mid+1, end, temp);

//归并，使小区间有序
int begin1 = begin, end1 = mid,
begin2 = mid + 1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
temp[i++] = a[begin1++];
}
else
{
temp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
temp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
temp[i++] = a[begin2++];
}
memcpy(a + begin, temp + begin,(end - begin + 1)*sizeof(int));
}``````

(2)非递归写法

``````void merge_sort_nor(int* a, int n)
{
int* temp = (int*)malloc(sizeof(int) * n);
if (temp == NULL)
{
exit(-1);
}
int gap = 1;
while (gap<n)
{
//i i+gap-1;i+gap i+2*gap-1;
int j = 0;
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1,
begin2 = i + gap, end2 = i + 2 * gap - 1;

//修正边界
if (end1 >= n)
{
end1 = n - 1;
//修正成不存在的区间
begin2 = n;
end2 = n - 1;
}
else if (begin2 >= n)
{
begin2 = n;
end2 = n - 1;
}
else if (end2 >= n)
{
end2 = n - 1;
}
j = i;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])//加个=，使他可以稳定
{
temp[j++] = a[begin1++];
}
else
{
temp[j++] = a[begin2++];
}
}
while (begin1 <= end1)
{
temp[j++] = a[begin1++];
}
while (begin2 <= end2)
{
temp[j++] = a[begin2++];
}
}
memcpy(a, temp, 2*gap* sizeof(int));
gap *= 2;
}
free(temp);
}``````

1.稳定性：相对顺序不变。eg: 1 2 3 3 4 2，在排序之后，2的相对顺序不变，5的相对顺序不变。

2.内排序：在内存上进行的排序

eg.有10亿个int整数，需要4G的空间，对这些数字排序。思想：为了提高速度，先把这些数字分成四份，把每一份放在内存里面归并排序再写入文件，之后对这些文件进行归并排序。（fprintf/fscanf)。

0 条评论