元素类型声明
typedef struct
{
int key;
int value;
} RecType;
交换算法
void swap(RecType &a,RecType& b)
{
RecType tmp;
tmp = a;
a = b;
b = tmp;
}
直接插入排序
不带哨兵
版本一
void InsertSort(int A[],int n)
{
int i,j,temp;
for(i = 1;i < n;i++)
{
if(A[i] < A[i - 1])
{
temp = A[i];
for(j = i - 1;j >= 0 && A[j] > temp;--j)
{
A[j + 1] = A[j];
}
A[j + 1] = temp;
}
}
}
版本二
void InsertSort(RecType R[],int n)
{
int i,j;
RecType tmp;
for(i = 1;i < n;i++)
{
if(R[i].key < R[i - 1].key)
{
tmp = R[i];
j = i - 1;
do
{
R[j + 1] = R[j];
j--;
} while(j >= 0 && R[j].key > tmp.key);
R[j + 1] = tmp;
}
}
}
版本三
void InsertSort(RecType R[],int n)
{
int i,j;
RecType tmp;
for(i = 1;i < n;i++)
{
tmp = R[i];
j = i - 1;
while(j >= 0 && tmp.key < R[j].key)
{
R[j + 1] = R[j];
j = j - 1;
}
R[j + 1] =tmp;
}
}
带有哨兵
void InsertSort(int A[],int n)
{
int i,j;
for(i = 2;i <= n;i++)
{
if(A[i] < A[i - 1])
{
A[0] = A[i];
for(j = i - 1;A[0] < A[j];--j)
{
A[j + 1] = A[j];
}
A[j + 1] = A[0];
}
}
}
折半插入排序
不带哨兵
void BinInsertSort(RecType R[],int n)
{
int i,j,low,high,mid;
RecType tmp;
for(i = 1;i < n;i++)
{
if(R[i].key < R[i - 1].key)
{
tmp = R[i];
low = 0;
high = i - 1;
while(low <= high)
{
mid = (low + high) / 2;
if(tmp.key < R[mid].key)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
for(j = i - 1;j >= high + 1;j--)
{
R[j + 1] = R[j];
}
R[high + 1] = tmp;
}
}
}
带有哨兵
void InsertSort(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 >= high + 1;j--)
{
A[j + 1] = A[j];
}
A[high + 1] = A[0];
}
}
希尔排序
不带哨兵
void ShellSort(RecType R[],int n)
{
int i,j,d;
RecType tmp;
d = n /2;
while(d > 0)
{
for(i = d;i < n;i++)
{
tmp = R[i];
j = i - d;
while(j >= 0 && tmp.key < R[j].key)
{
R[j + d] = R[j];
j = j - d;
}
R[j + d] = tmp;
}
d = d / 2;
}
}
带有哨兵
void ShellSort(int A[],int n)
{
int i,j,d;
for(d = n / 2;d >= 1;d = d / 2)
{
for(i = d + 1;i <= n;i++)
{
if(A[i] < A[i - d])
{
A[0] = A[i];
for(j = i - d;j > 0 && A[0] < A[j];j = j -d)
{
A[j + d] = A[j];
}
A[j + d] = A[0];
}
}
}
}
冒泡排序
非递归实现
优化前
void BubbleSort(RecType R[],int n)
{
int i,j;
RecType temp;
for(i = 0;i < n - 1;i++)//n-1趟排序
{
//j:i+1~n-1
//i=0 j:1~n-1
//i=1 j:2~n-1 ...
//i = n-2 j:n-1
for(j = n - 1;j > i;j--)
{
if(R[i].key < R[j - 1].key)
{
swap(R[j],R[j - 1]);
}
}
}
}
优化后
版本一
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 - 1] > A[j])
{
swap(A[j - 1],A[j]);
flag = true;
}
}
if(flag == false)
{
return;
}
}
}
版本二
void BubbleSort(RecType R[],int n)
{
int i,j;
RecType temp;
bool exchange;
for(i = 0;i < n - 1;i++)
{
exchange = true;
for(j = n - 1;j > i;j--)
{
if(R[j].key < R[j - 1].key)
{
swap(R[j],R[j - 1]);
exchange = false;
}
}
if(exchange == false)
{
return;
}
}
}
递归实现
冒泡排序采用交换方式将无序区中的最小元素放到开头处。
设f(a,n,i)用于将无序区a[i…n-1] (共n-i个元素)中的最小元素交换到a[i]处,是大问题,则f(a,n,i+1)用于将无序区a[i+1…n-1] (共n-i-1个元素)中的最小元素换到a[i+1]处,是小问题。当i=n-1时所有元素有序(此时无序区为a[n-1…n-1],即无序区中只有一个元素,而一个元素可以看成是有序的),算法结束。
对应的递归模型如下:
当i = n - 1时,f(a,n,i)=不做任何事情,算法结束
否则,对a[i…n−1]中的元素序列从a[n−1]开始进行相邻元素比较,若相邻两元素反序则将两者交换;若没有交换则返回,否则执行f(a,n,i+1);
#include <iostream>
void swap(int &x,int &y)//交换x和y值
{
int tmp = x;
x = y;
y = tmp;
}
void disp(int a[],int n)//输出a中的所有元素
{
int i;
for(i = 0;i < n;i++)
{
cout << a[i] << " ";
}
cout << endl;
}
void BubbleSort(int a[],int n,int i)//递归的冒泡排序
{
int j;
bool exchange;
if(i == n - 1)
{
return;//满足递归出口条件
}
else
{
exchange = false;//置exchange为false
for(j = n - 1;j > i;j--)//将a[i..n-1]中的最小元素放到a[i]处
{
if(a[j] < a[j - 1])//当相邻元素反序对
{
swap(a[j],a[j - 1]);//a[j]和a[j - 1]进行交换,将无序区中的最小元素前移
}
}
if(exchange == false)
{
//未发生交换则返回
return;
}
else//发生交换则继续递归调用
{
BubbleSort(a,n,i+1);
}
}
}
void main()
{
int n = 10;
int a[] = {2,5,1,7,10,6,9,4,3,8};
cout << "排序前: ";
disp(a,n);
BubbleSort(a,n,0);
cout << "排序后: ";
disp(a,n);
}
快速排序
基于交换
#define MaxSize 100
typedef struct
{
ElemType data[MaxSize];
int length;
} SqList;
void partition(SqList *&L)
{
int i =0;//前指针
int j = L->length - 1;//后指针
ElemType pivot = L->data[0];//以data[0]为基准
while(i < j)
{
//从后往前扫描,找一个小于等于pivot的元素
while(i < j && L->data[j] > pivot)
{
j--;
}
//从前往后扫描,找一个大于基准的元素
while(i < j && L->data[i] <= pivot)
{
i++;
}
if(i < j)
{
swap(L->data[i],L->data[i]);
}
}
swap(L->data[0],L->data[i]);
}
基于移动
版本一
int partition(RecType R[],int s,int t)
{
int i = s;
int j = t;
RecType tmp = R[i];
while(i < j)
{
while(i < j && R[j].key >= tmp.key)
{
j--;
}
R[i] = R[j];
while(i < j && R[i].key <= tmp.key)
{
i++;
}
R[j] = R[i];
}
R[i] = tmp;
return i;
}
void QuickSort(RecType R[],int s,int t)
{
int i;
if(s < t)
{
i = partition(R,s,t);
QuickSort(R,s,i-1);
QuickSort(R,i+1,t);
}
}
版本二
//用第一个元素将待排序序列划分成左右两个部分
int Partition(int A[],int low,int high)
{
int pivot = A[low];//第一个元素作为枢轴
while(low < high) //用low、high搜索枢轴的最终位置
{
//找一个小于枢轴的元素,往前移
while(low < high && A[high] >= pivot)
{
--high;
}
A[low] = A[high];//比枢轴小的元素移动到左端
//找大于枢轴的元素,往后移
while(low < high && A[low] <= pivot)
{
++low;
}
A[high] = A[low];//比枢轴大的元素移动到右边
}
A[low] = pivot;//枢轴元素放到最终位置
return low;//返回存放枢轴的最终位置
}
//快速排序
void QuickSort(int A[],int low,int high)
{
if(low < high) //递归跳出的条件
{
int pivotpos =Partition(A,low,high);//划分
QuickSort(A,low,pivotopos - 1);//划分左子表
QuickSort(A,pivotpos+1,high);//划分右子表
}
}
简单选择排序
非递归实现
版本一
void SelectSort(int A[],int n)
{
int i,j,min;
for(i = 0;i < n - 1;i++)//一共进行n-1趟
{
min = i;//每趟排序起始位置 记录最小元素的位置
for(j = i + 1;j < n;j++)//在A[i...n-1]中选择最小的元素
{
if(A[j] < A[min])//更新最小元素位置
{
min = j;
}
}
if(min != i)
{
swap(A[i],A[min]);//封装的swap函数共移动元素3次
}
}
}
版本二
int Min(int a[],int n,int i)
{
int k = i;//k保存最小元素的下标
int j;//j遍历有序区未排序的元素,从而找到一个最小的加入全局有序区
for(j = i + 1;j < n;j++)
{
if(a[j] < a[k])
{
k = j;
}
}
return a[k];//n个记录中找出最小记录需要进行n-1次比较
}
void SelectSort(RecType R[],int n)
{
int i,j,k;
for(i = 0;i < n - 1;i++)//做第i趟排序
{
k = i;
for(j = i + 1;j < n;j++)
{
if(R[j].key < R[k].key)
{
k = j;
}
}
if(k != i)
{
swap(R[i],R[k]);//R[i] <=> R[k]
}
}
}
递归实现
将a[0…n-1]分为有序区a[0…i-1]和无序区a[i…n-1]两个部分,有序区中的所有元素都不大于无序区中的元素,初始时有序区为空(即i=0).经过n-1趟排序(i=1~n-2),每趟排序采用不同方式将无序区中的最小元素移动到无序区的开头,即a[i]处.
简单选择排序采用简单比较方式在无序区中选择最小元素并放到开头处。
设f(a,n,i)用于在无序区a[i…n-1] (共n-i个元素)中选择最小元素并放到a[i]处,是"大问题",则f(a,n,i+1)用于在无序区a[i+1…n-1] (共n-i-1个元素)中选择最小元素并放到a[i+1]处,是"小问题"。当i=n-1时所有元素有序(此时无序区为a[n-1…n-1]),即无序区中只有一个元素,而一个元素可以看成是有序的,算法结束。对应的递归模型如下:
#include <iostream>
using namespace std;
void swap(int &x,int &y)//交换x和y值
{
int tmp = x;
x = y;
y = tmp;
}
void disp(int a[],int n)//输出a中的所有元素
{
int i;
for(i = 0;i < n;i++)
{
cout << a[i] << " ";
}
cout << endl;
}
void SelectSort(int a[],int n,int i)//递归的简单选择排序
{
int j,k;
if(i == n - 1)
{
return;//满足递归出口条件
}
else
{
k = i;//k记录a[i..n-1]中最小元素的下标
for(j = i + 1;j < n;j++)//在a[i..n-1]中找最小元素a[k]
{
if(a[j] < a[k])
{
k = j;
}
}
if(k != i)//若最小元素不是a[i]
{
swap(a[i],a[k]);//a[i]和a[k]交换
}
SelectSort(a,n,i+1);
}
}
void main()
{
int n = 10;
int a[] = {2,5,1,7,10,6,9,4,3,8};
cout << "排序前: ";
disp(a,n);
SelectSort(a,n,0);
cout << "排序后: ";
disp(a,n);
}
堆排序
版本一
//建立大根堆
void BuildMaxHeap(int A[],int len)
{
for(int i = len / 2;i > 0;i--)//从后往前调整所有的非终端结点
{
HeadAdjust(A,i,len);
}
}
//将以k为根的子树调整为大根堆
void HeadAdjust(int A[],int k,int len)
{
A[0] = A[k];//A[0]暂存子树的根结点
for(int i = 2 * k;i <= len;i = i * 2) //沿key较大的子结点向下筛选
{
if(i < len && A[i] < A[i + 1])
{
i++;//取key较大的子结点的下标
}
if(A[0] >= A[k])
{
break;//筛选结束
}
else
{
A[k] = A[i];//将A[i]调整到双亲结点上
k = i;//修改k值,以便继续筛选
}
}
A[k] = A[0];//被筛选结点的值放入最终位置
}
void HeapSort(int A[],int len)
{
BuildMaxHeap(A,len);//初始建堆
for(int i = len;i > 1;i--)//n-1趟的交换和建堆过程
{
swap(A[i],A[1]);//堆顶元素和堆底元素互换
HeadAdjust(A,1,i - 1);//把剩余的待排序的元素整理成堆
}
}
版本二
//筛选或调整算法
void sift(RecType R[],int low,int high) //调整堆的算法
{
int i = low;
int j = 2 * i;//R[j]是R[i]的左孩子
RecType tmp = R[i];
while(j <= high)
{
if(j < high && R[j].key < R[j + 1].key)
{
j++;//保证j指向较大的孩子
}//最后一个分支结点至少会有一个左孩子,并且只有它才有一个左孩子。
if(tmp.key < R[j].key) //双亲小
{
R[i] = R[j];//将R[j]调整到双亲结点位置
i = j;//修改i和j值,以便继续向下筛选
j = 2 * i;
}
else
{
break;//双亲大,不再调整
}
}
R[i] = tmp;
}
//循环建立初始堆
for(i = n / 2;i >= 1;i--)
{
sift(R,i,n);
}
//堆排序算法
void HeapSort(RecType R[],int n)
{
int i;
for(i = n / 2;i >= 1;i--) //循环建立初始堆
{
sift(R,i,n);
}
for(i = n;i >= 2;i--) //进行n-1次循环,完成堆排序
{
swap(R[1],R[i]);//R[1]<=>R[i]
sift(R,1,i - 1);//筛选R[1]结点,得到i-1个结点的堆 n-1次调整堆顶
}
}
归并排序
二路归并排序
Merge():一次二路归并,将两个相邻有序子序列归并为一个子序列
void Merge(RecType R[],int low,int mid,int high)
{
RecType* R1;
int i= low,j = mid + 1,k = 0;//k是R1的下标,i、j分别是第1、2段的下标
R1 = (RecType*)malloc(sizeof(RecType) *(high - low + 1));//空间复杂度O(high - low + 1)
while(i <= mid && j <= high)
{
if(R[i].key <= R[j].key) //将第1段的记录放入R1中
{
R1[k] = R[i];
i++;
k++;
}
else //将第2段的记录放入R1中
{
R1[k] = R[j];
j++;
k++;
}
}
while(i <= mid) //将第一段的余下部分复制到R1中
{
R1[k] = R[i];
i++;
k++;
}
while(j <= high) //将第2段的余下部分复制到R1
{
R1[k] = R[j];
j++;
k++;
}
for(k = 0,i = low;i <= high;i++,k++)//将R1复制回R1中
{
R[i] = R1[k];
}
free(R1);
}
基于递归实现
自顶向下的递归二路归并排序算法
版本一
void MergeSortDC(RecType R[],int low,int high)
{
//对R[low..high]进行二路归并排序
int mid;
if(low < high)
{
mid = (low + high) / 2;
MergeSortDC(R,low,mid);
MergeSortDC(R,mid + 1,high);
Merge(R,low,mid,high);
}
}
//自顶向下的二路归并算法
void MergeSort1(RecType R[],int n)
{
MergeSortDC(R,0,n - 1);
}
版本二
int * B = (int*)malloc(n * sizeof(int));//辅助数组B
//A[low..mid]和A[mid + 1..high]已经各自有序,将两个部分归并
void Merge(int A[],int low,int mid,int high)
{
int i,j,k;
for(k = low;k <= high;k++)
{
B[k] = A[k];//将A中所有元素复制到B中
}
for(i = low,j = mid + 1,k = i;i <= mid && j <= high;k++)
{
if(B[i] <= B[j])
{
A[k] = B[i++];
}
else
{
A[k] = B[j++];
}
}
while(i <= mid)
{
A[k++] = B[i++];
}
while(j <= high)
{
A[k++] = B[j++];
}
}
void MergeSort(int A[],int low,int high)
{
if(low < high)
{
int mid = (low + high) / 2;//从中间划分
MergeSort(A,low,mid);//对左半部分进行归并排序
MergeSort(A,mid + 1,high);//对右半部分进行归并排序
Merge(A,low,mid,high);//归并
}
}
基于非递归实现
void MergePass(RecType R[],int length,int n)
{
int i;
for(i = 0;i + 2* length - 1 < n;i = i + 2 * length)//归并length长的两相邻子表
{
Merge(R,i,i + length - 1,i + 2* length - 1);
}
//如果只剩下一个子表的话,下面的代码不会成立,一个子表自然就不会归并(只有两两才会归并)
if(i + length - 1 < n - 1) //余下两个子表,后者长度小于length
{
Merge(R,i,i + length - 1,n - 1);//归并这两个子表
}
}
void MergeSort(RecType R[],int n)
{
int length;
for(length = 1;length < n;length = 2* length)
{
MergePass(R,length,n);
}
}
k路归并排序(k >= 3)
3路归并排序
算法描述:
void Merge3(LinkNode* L0,LinkNode* L1,LinkNode* L2,LinkNode* &L)
{
LinkNode* p0 = L0->next;
LinkNode* p1 = L1->next;
LinkNode* p2 = L2->next;
while(p0 \ p1 \ p2 均没有扫描完)
{
比较p0->data\p1->data\p2->data 复制最小元素产生结点s
将结点s采用尾插法链接到L中
后移最小元素的指针
}
循环结束后
将L0\L1进行二路归并
将L0\L2进行二路归并
将L1\L2进行二路归并
}
- L0 L1 L2 对应段号为0~2
- 用3个指针p0 p1 p2 指向它们的当前结点
- 将3个当前结点存放在x数组中,指针为空则对应结点取为无穷
- 在x数组中查找最小结点的段号mink,若为无穷,则mink=-1
//通过简单比较找到最小元素的段号
int Min(T x[])
{
int i,mink = 0;
for(i = 0;i < 3;i++)
{
if(x[i] < x[mink])
{
mink = i;
}
}
if(x[mink] == INF)//若最小结点的值为无穷,归并完毕,返回-1
{
return -1;
}
else
{
return mink;
}
}
void Merge3(LinkNode* L0,LinkNode* L1,LinkNode* L2,LinkNode* &L)
{
int mink;
LinkNode* p0 = L0->next;
LinkNode* p1 = L1->next;
LinkNode* p2 = L2->next;
LinkNode* s,*r;
L = (LinkNode*)malloc(sizeof(LinkNode));
r = L;
T x[3];//存放三个段当前比较的元素
x[0] = (p0 != NULL)?p0->data:INF;//将3个段的结点值复制到x中
x[1] = (p1 != NULL)?p1->data:INF;
x[2] = (p2 != NULL)?p2->data:INF;
while(true)
{
mink = Min(x);//求出最小的段号
if(mink == -1)//所有结点归并完毕
{
break;//全面归并完毕,退出循环
}
else
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x[mink];//复制建立结点s
r->next = s;//将结点s链接到L
r = s;//移动最小结点所在段的指针
switch(mink)
{
case 0:p0 = p0->next;x[0] = (p0 != NULL)?p0->data:INF;break;
case 1:p1 = p1->next;x[1] = (p1 != NULL)?p1->data:INF;break;
case 2:p2 = p2->next;x[2] = (p2 != NULL)?p2->data:INF;break;
}
}
}
r->next = NULL;
}
k路归并排序
void MergeK(LinkNode* L[k],LinkNode* &L1) //k为常量
{
int mink;
LinkNode* p[k];
for(int i = 0;i < k;i++)
{
p[i] = L[i]->next;
}
LinkNode* s,*r;
L1 = (LinkNode*)malloc(sizeof(LinkNode));
r = L1;
T x[k];//存放k个段当前比较的元素
for(int j = 0;j < k;j++) //将k个段的当前结点值复制到x中
{
x[j] = (p[j] != NULL)?p[j]->data:INF;
}
while(true)
{
mink = Min(x);//求出最小结点的段号
if(mink == -1) //所有结点归并完毕
{
break;//全部归并完毕,退出循环
}
else
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x[mink];//复制建立结点s
r->next = s;
r =s;//将结点s链接到L
p[mink] = p[mink]->next;
x[mink] = (p[mink]!= NULL)?p[mink]->data:INF);//移动最小结点所在段的指针
}
}
r->next = NULL;
}
基数排序
#define MAXE 20 //线性表中最多元素个数
#define MAXR 10 //基数的最大取值
#define MAXD 8 //关键字位数的最大取值
typedef struct node
{
char data[MAXD];//记录的关键字定义的字符串
struct node* next;
} RecType1;//单链表中每个结点的类型
void RadixSort(RecType1 *&p,int r,int d)
{
//p为待排序链表指针
//r为基数
//d为关键字位数
RecType1 *head[MAXR],*tail[MAXR],*t;//定义各链队的首尾指针
int i,j,k;
for(i = 0;i < d;i++) //从低位到高位做d趟排序
{
for(j = 0;j < r;j++) //初始化各链队、首尾指针
{
head[j] = tail[j] = NULL;//设不带头结点
}
//分配
while(p != NULL) //对于原链表的每个结点循环
{
k = p->data[i] - '0';//找第k个链队
if(head[k] == NULL)
{
head[k] = p;
tail[k] = p;
}
else
{
tail[k]->next = p;
tail[k] = p;
}
p = p->next;//取下一个待排序的结点
}
p = NULL;
for(j = 0;j < r;j++) //对于每一个链队循环进行收集
{
if(head[j] != NULL)
{
if(p == NULL)
{
p = head[j];
t = tail[j];
}
else
{
t->next = head[j];
t = tail[j];
}
}
}
t->next = NULL;//最后一个结点的next域置为NULL
}
}