1、插入排序:
1)直接插入排序:
哨兵版:
void insertSort(int A[], int n)
{
int i, j;
for(i = 2; i <= n; i++)
{
A[0] = A[i]; //负责为哨兵,A[0]不存放元素
for(j = i - 1; A[0] < A[j]; j--)
A[j+1] = A[j];
A[j+1] = A[0];
}
}
普通版:
void insertSort2(int A[], int n)
{
int i, j;
int temp;
for(i = 1; i < n; i++)
{//A[0]放元素
if(A[i] < A[i-1])
{
temp = A[i]; //暂存A[i];
for(j = i-1; j >= 0 &&A[j] > temp; --j)
A[j+1] = A[j];
A[j+1] = temp;
}
}
}
2)折半插入排序:在排好的序的部分折半查找插入位置
void insertSort3(int A[], int n)
{
int i,j,low,high,mid;
for(i = 2; i <= n; i++)
{
A[0] = A[i];
low = 1; high = i - 1;
while(low <= high)
{
mid = (low + high)/2;
if(A[mid] > A[0]) high = mid - 1;
else low = mid+1;
}
for(j = i-1; j >= low; --j)
{//low指向要插入的位置low==high+1
A[j+1] = A[j];
}
A[low] = A[0];
}
}
2、希尔排序:
严版:
void shellInsert(int A[],int n,int dk)
{
int i, j;
for(i = 1+dk; i <= n; i++)
{//对增量为dk的序列进行直接插入排序
if(A[i] < A[i-dk])
{
A[0] = A[i]; //暂存A[i]非哨兵,A[0]不存放元素;也可用temp代替
for(j = i-dk; j > 0 && A[0] > A[j]; j -= dk)
A[j+dk] = A[j];
A[j+dk] = A[0];
}
}
}
void shellSort(int A[], int n, int delta[], int t)
{//A为待排序列,n为其长度,delta为增量序列,t为其长度
for(int k = 0; k < t; k++)
{//一个增量一趟
shellInsert(A, n, delta[k]);
}
}
3、冒泡排序:
void swap(int &a,int &b)
{
int temp = a;
a = b;
b = temp;
}
void bubbleSort(int A[], int n)
{//升序,从后往前冒
for(int i = 0; i < n-1; i++)
{
bool flag = false; //本趟是否发生过交换
for(int j=n-1; j > i; j--)
{
if(A[j] < A[j-1])
{
swap(A[j], A[j-1]);
flag = true;
}
}
if(flag == false) //没有交换过,则已是升序
return ;
}
}
4、快速排序:找到的所有版本,区别就是partition
1)初始版本:
#include<iostream>
using namespace std;
int partition(int A[],int low,int high)
{
int pivotkey = A[low]; //选左边第一个pivotkey
int start = low; //暂存pivotkey的下标
while(low < high)
{
while(low < high && A[high] >= pivotkey) high--;
while(low < high && A[low] <= pivotkey) low++;
if(low < high)
{
swap(A[low],A[high]);
}
}
swap(A[low],A[start]); //此时low == high,且A[low]必然是小于等于pivotkey的
return low;
}
void QSort(int A[], int low, int high)
{
if(low < high)
{
int pivotloc = partition(A, low, high);
QSort(A, low, pivotloc-1);
QSort(A, pivotloc+1, high);
}
}
void QuickSort(int A[], int n)
{
QSort(A,0,n-1);
}
int main()
{
int A[10] = {4,2,1,4,5,6,7,8,9,3};
QuickSort(A,10);
for(int i = 0; i < 10; i++)
{
cout<<A[i]<<endl;
}
return 0;
}
2)挖坑法:对上面的改进,严书上只有这个(但是暨大考过其他版本的,所以汇总下)
#include<iostream>
using namespace std;
int partition(int A[],int low,int high)
{
int pivotkey = A[low];
while(low < high)
{
while(low < high && A[high] >= pivotkey) high--;
A[low] = A[high];
while(low < high && A[low] <= pivotkey) low++;
A[high] = A[low];
}
A[low] = pivotkey;
return low;
}
3)前后指针法:
最右边的枢纽:
int partition(int A[],int low,int high)
{
int pivotkey = A[high]; //最右边为枢纽
int i = low - 1;
for(int j = low; j <= high-1; j++)
{
if(A[j] < pivotkey)
{
i++;
swap(A[i], A[j]);
}
}
swap(A[i+1],A[high]); //[low,i]、i+1、[i+2,high]
return i+1;
}
最左边的为枢纽:
int partition(int A[],int low,int high)
{
int pivotkey = A[low]; //最左边为枢纽
int i = high+1;
for(int j = high; j > 0; j--)
{
if(A[j] > pivotkey)
{
i--;
swap(A[i], A[j]);
}
}
swap(A[i-1],A[low]); //[low,i]、i+1、[i+2,high]
return i-1;
}
王道这样写的,感觉好点
int partition(int A[],int low,int high)
{
int pivotkey = A[low]; //最左边为枢纽
int i = low;
for(int j = low+1; j <= high; j++)
{
if(A[j] < pivotkey)
{
swap(A[++i], A[j]);
}
}
swap(A[i],A[low]);
return i;
}
随机位置:
int partition(int A[], int low,int high)
{
int random_index = rand()%(high-low+1);
swap(A[low],A[random_index]);
int pivotkey = A[low];
while(low < high)
{
while(low < high && A[high] >= pivotkey)high--;
A[low] = A[high];
while(low < high && A[low] <= pivotkey) low++;
A[high] = A[low];
}
A[low] = pivotkey;
return low;
}
int partition(int A[], int low, int high)
{
int random_index = rand()%(high-low+1);
swap(A[low],A[random_index]);
int pivotkey = A[low];
int i = low;
for(int j = low+1;j <= high; j++)
{
if(A[j] < pivotkey)
{
swap(A[++i],A[j]);
}
}
swap(A[i],A[low]);
return i;
}
暨大考题2020:填空
int partition(int* A, int N, int p, int r)
{ int x = A[r];
int i = //(5) ;
for (int j = p; j<=r-1; j++){
if ( //(6) ){
i = i + 1;
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
int temp = A[i+1];
A[i+1] = A[r];
A[r] = temp;
return //(7) ;
}
void QuickSort(int* A, int N, int p, int r)
{
int q;
if ( //(8) ){
q = partition(A, N, p, r);
QuickSort( //(9) );
QuickSort( //(10) );
}
return;
}
void main()
{ QuickSort(A, N, 0,N-1);
return 0;
}
4)Hoare分区方案:第1个版本的另一种写法
int partition(int arr[],int low, int hight)
{
int pivot = arr[low];
int i = low - 1;
int j = hight + 1;
while(true)
{
while(arr[++i] < pivot); //找 >= pivot的
while(arr[--j] > pivot); //找 <= piovt的
if(i >= j)
{
return j;
}
swap(arr[i],arr[j]);
}
}
5)非递归版本:分区用哪个版本无所谓
#include<iostream>
#include<stack>
using namespace std;
int partition(int A[],int low,int high)
{
int pivotkey = A[low];
while(low < high)
{
while(low < high && A[high] >= pivotkey) high--;
A[low] = A[high];
while(low < high && A[low] <= pivotkey) low++;
A[high] = A[low];
}
A[low] = pivotkey;
return low;
}
void QSort(int A[], int low, int high)
{
stack<int>stk;
if(low < high)
{
stk.push(low); //先左后右进栈,先右后左出栈
stk.push(high);
while(!stk.empty())
{
int right = stk.top(); stk.pop();
int left = stk.top(); stk.pop();
int pivotloc = partition(A,left, right); //枢纽下标
if(left < pivotloc - 1)
{//左边还有两个及以上的元素
stk.push(left);
stk.push(pivotloc-1);
}
if(right > pivotloc + 1)
{//左边还有两个及以上的元素
stk.push(pivotloc+1);
stk.push(right);
}
}
}
}
void QuickSort(int A[], int n)
{
QSort(A,0,n-1);
}
int main()
{
int A[10] = {4,2,1,4,5,6,7,8,9,3};
QuickSort(A,10);
for(int i = 0; i < 10; i++)
{
cout<<A[i]<<endl;
}
return 0;
}
队列版:
void QSort(int A[], int low, int high)
{
queue<int>q;
if(low < high)
{
q.push(low);
q.push(high);
while(!q.empty())
{
int left = q.front(); q.pop();
int right = q.front(); q.pop();
int pivotloc = partition(A,left, right); //枢纽下标
if(left < pivotloc - 1)
{//左边还有两个及以上的元素
q.push(left);
q.push(pivotloc-1);
}
if(right > pivotloc + 1)
{//左边还有两个及以上的元素
q.push(pivotloc+1);
q.push(right);
}
}
}
}
快排扩展:第k小的数
int kth_elem(int A[],int low, int high, int k)
{
int pivot = A[low];
int left = low;
int right = high;
while(left < right)
{
while(left < right && A[right] >= pivot) right--;
A[left] = A[right];
while(left < right && A[left] <= pivot) left++;
A[right] = A[left];
}
A[left] = pivot; //left == right
//上面和快排分区没什么不同
if(left == k)
{
return A[left];
}
else if(left > k)
{
return kth_elem(A, low, left-1, k);
}
else
{
return kth_elem(A, left+1, high, k);
}
}
5、堆排序:
顺序存储的完全二叉树下标
- 从
0
开始时,n
个结点,最大分支结点编号是((n-1)-1)/2
,双亲编号是(i-1)/2
,都是向下取整. - 从
1
开始时,n
个结点,最大分支结点编号是n/2
,双亲编号是i/2
,都是向下取整。
基于大根堆:下标从1开始
void HeapAdjust(int A[], int k, int len)
{//自顶向下调整siftDown
A[0] = A[k];
for(int i = 2*k; i < len; i*=2)
{
if(i < len && A[i] < A[i+1])
{
i++; //取较大的子女下标
}
if(A[0] >= A[i]) break;
A[k] = A[i];
k = i;
}
A[k] = A[0];
}
void BuildMaxHeap(int A[], int len)
{//建堆
for(int i = len/2; i > 0; i--)
{//len/2是编号最大的分支结点
HeapAdjust(A, i, len);
}
}
void HeapSort(int A[], int len)
{
BuildMaxHeap(A,len); //建立初始大根堆
for(int i = len; i > 1; i--)
{
swap(A[i], A[1]); //输出堆顶元素(输出到堆底)
HeapAdjust(A, 1, i-1); //调整,把剩下的i-1个元素组成堆
}
}
小根堆:下标从0开始(多写了,加了插入和删除,如果只是用小根堆来排序不用写这么麻烦)
const int heapSize = 50;
typedef int HElemType;
typedef struct {
HElemType elem[heapSize];
int curSize;
}minHeap;
void siftDown(minHeap &heap, int i, int n)
{
HElemType cur = heap.elem[i]; //i是双亲,j是i的值更小的子女
for(int j = 2*i+1; j < n; j = 2*j +1)
{
if(j < n-1 && heap.elem[j] > heap.elem[j+1]) j++; //有右兄弟,且右兄弟更小
if(cur <= heap.elem[j]) break; //双亲比子女更小,停止向下
else{
heap.elem[i] = heap.elem[j]; //双亲比子女
i = j;
}
}
heap[i] = cur;
}
viod siftUp(minHeap &heap, int start)
{//自底向下调整小根堆
HElemType cur = heap.elem[start];
int j = start; //j是子女
int i = (j-1)/2; //i是j的双亲
while(j > 0)
{
if(heap.elem[i] <= cur) break; //双亲更小停止向上
else{
heap.elem[j] = heap.elem[i]; //双亲比子女大,让子女上去(把双亲拉下来)
j = i; //上一层
i = (i-1)/2; //上一层
}
}
heap.elem[j] = cur;
}
void insert(minHeap &heap, int x)
{
if(heap.curSize == heapSize) return false;
heap.elem[heap.curSize] = x;
siftUp(heap,heap.curSize);
heap.curSize++; return true;
}
void delete(minHeap &heap, int &x)
{//删除堆顶元素,并赋值给x
if(heap.curSize == 0) return false;
x = heap.elem[0];
heap.elem[0] = heap.elem[--heap.curSize];
siftDown(heap, 0, heap.curSize);
return true;
}
void creatMinHeap(minHeap &heap, ElemType arr[], int n)
{//创建小根堆
for(int i = 0; i < n; i++) heap.elem[i] = arr[i];
heap.curSize = n;
for(int i = (n-2)/2; i >= 0; i--)
{
siftDown(heap, i, heap.curSize);
}
}
HElemType* heapSort(minHeap heap)
{
HElemType *res = new HElemType[heap.curSize];
int j = 0;
for(int i = heap.curSize-1; i >= 0; i--)
{
res[j++] = heap.elem[0];
swap(heap.elem[i],heap.elem[0]);
siftDown(heap, 0, i);
} //heap不是小根堆了
return res;
}
判断是不是小根堆:
bool isMinHeap(int A[], int len)
{
if(len%2 == 0) //len为偶数有一个单分支结点且是编号最大的分支结点
{
if(A[(len-2)/2] > A[len-1])
{
return false;
}
for(int i = (len-2)/2-1; i >= 0; i--)
{
if(A[i] > A[2*i+1] || A[i] > A[2*i+2])
{
return false;
}
}
}
else
{
for(int i = (len-2)/2; i >= 0; i--)
{
if(A[i] > A[2*i+1] || A[i] > A[2*i+2])
{
return false;
}
}
}
}
6、归并排序:
以前写的:归并排序
迭代版本:
void MergeSort(int arr[],int len)
{
int *a = arr;
int *b = new int[len]; //辅助数组
for(int seg=1; seg < len; seg += seg)
{
for(int start = 0; start < len; start += seg*2)
{
int low = start, mid = min(start+seg, len), high = min(start+seg*2,len);
int k = low;
int start1 = low, end1 = mid;
int start2 = mid, end2 = high;
while(start1 < end1 && start2 < end2)
b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
while(start1 < end1)
b[k++] = a[start1++];
while(start2 < end2)
b[k++] = a[start2++];
}
int *temp = a; //交换a和b的指向,让b下一轮还是指向辅助数组
a = b; //交换会让arr和辅助数组的地位在下一轮中互换
b = temp; //而每轮循环结束后,a都指向本轮归并结果数组
}
//结束上面语句后a指向的是排序后的数组,但因为arr和一开始的辅助数组角色互换
//所以,如果 a != arr就说明最后一轮arr是被当作辅助数组用的
//注:arr的指向是不会变的
if(a != arr)
{
for(int i = 0; i < len; i++)
{
b[i] = a[i]; //或者写成arr[i] = a[i];
}
b = a;
}
delete [] b;
}
递归版本:
void Merge(int A[], int temp[], int low, int mid, int high)
{
for(int k = low; k <= high; k++)
{
temp[k] = A[k];
}
for(int i = low, j= mid + 1, k = i;i <= mid&&j <=high; k++)
{
if(temp[i] <= temp[j]) A[k] = B[i++];
else A[k] = B[j++];
}
while(i <= mid) A[k++] = temp[i++];
while(j <= high) A[k++] = temp[j++];
}
void MSort(int A[],int temp[],int low,int high)
{
if(low < high)
{
int mid = (high - mid)/2;
MSort(A, temp, low, mid);
MSort(A, temp, mid+1, high);
Merge(A, temp, low, mid, high);
}
}
void MergeSort(int A[], int low, int high, int n)
{
int *temp = new int[n];
MSort(A, temp, low, high);
}
7、基数排序:
基数排序分两种:最高位优先MSD(Most Significant Digit first)和最低位优先LSD(Least Significant Digit first),MSD应该不考,以后再看,下面代码基于LSD.
#include<iostream>
#include<queue>
using namespace std;
int power(int di)
{
int res = 1;
for(int i = 0; i < di; i++) res *= 10;
return res;
}
void print(int A[],int len)
{
for(int i = 0; i < len; i++)
{
cout<<A[i]<<" ";
}
cout<<endl;
}
void RadixSort(int A[], int len, int d)
{
//print(A,len);
queue<int>qarr[10];
for(int i = 0; i < d; i++)
{
//分配
int pow = power(i);
for(int j = 0; j < len; j++){
int index = A[j]/pow% 10;
qarr[index].push(A[j]);
}
//收集,按qarr[0]、qarr[1].....收集结果为升序,反之为降序
int k = 0;
for(int j = 0; j < 10; j++)
{
while(!qarr[j].empty())
{
int cur = qarr[j].front(); qarr[j].pop();
A[k++] = cur;
}
}
}
//print(A,len);
}
int main()
{
int A[10] = {105,12, 3, 45,47, 31, 5,6,9,567};
RadixSort(A,10,3);
return 0;
}
注:上面代码不能处理负数情况,负数应该也不考