数据结构常用排序算法(c语言代码)
这是按王卓老师数据结构课的思路实现的排序算法,包括直接插入排序,折半插入排序,希尔排序,冒泡排序,快速排序,简单选择排序,堆排序,归并排序(有bug,有能力的自己修),基数排序,下面将简单的介绍一下每种排序的关键思路:(这里全都假设要把一个序列排位升序)
插入排序:
直接插入排序:
假设前 i-1个元素已经排好,从第i个元素开始向前进行比较,若小于则继续向前比较,若大于第j个元素,则将 j-1到 i-1个元素向后移动一个位置,把第 i 个元素插入到 j+1 位置。
折半插入排序:
与直接插入排序不同的是,查找插入位置时用了折半查找的思路,还是假设从第i个元素开始,设low=1,high=i-1,mid=(low+high)/2,将第i个元素与mid位置的元素进行比较,若小于,则在mid左侧序列再进行折半查找,令high=mid-1;若大于,则在mid右侧序列在进行折半查找,令low=mid+1,直至low=mid为止,最后high+1为要插入位置,对应元素后移,将第 i 个元素插入对应位置
希尔排序:
希尔排序,其实是进行多次直接插入排序,只不过每次向前比较的间隔不一样,直接插入排序的间隔为1,即每次与前一个元素进行比较,希尔排序设置一个dk[ ]数组,用于存放不同的间隔,对每个间隔进行插入排序。
交换排序:
冒泡排序:
从第一个元素开始,两两进行比较,若为逆序则交换位置,若为顺序,则不动,继续比较后一个元素,直到比较到最后一个元素,每一趟比较都把最大的元素放到了数组末尾,所以一共需要比较 序列长度-1 次。
快速排序:
随机选取第 i 元素,设置两个指针low和high分别指向最低元素和最高位置元素,先从高位置像第位置找一个比 i 元素值小的元素,放到最低位置,low++,再从低位置向高位置找一比 i元素值大的元素,放到最高位置,high–,重复上述过程,直至high=low,最后将 i 元素放到low位置处,就是一个升序的序列。
简单选择排序:
顾名思义,想法比较简单,从序列中找到最大的元素,放到序列末尾,在剩余的序列中,重复此操作。
堆排序:
先讲两个概念:大根堆,小根堆
大根堆:即满足以下条件的完全二叉树:每一个非叶子结点都大于他的左右孩子
若有了大根堆后,如何进行排序?先输出根节点,再将剩余的结点在构成一个大根堆,再输出根节点,再构成大根堆,重复上述操作,即能得到一个升序的序列,如何调整剩余结点成大根堆/
堆的调整:将堆顶元素输出后,选取编号最大的元素作为新的根节点,比较左右子树大小,把最大的与其交换,对子树也进行调整,若都比根节点小,则不动。
归并排序:
归并排序先把一个完整的序列拆分成 数量为 序列长度 个 的 元素数量为1的数组,并两个一组进行归并,并构成一组新的排好序的数组,再对新排好序的几组数组,两两进行归并,直至最后归并为一个序列。
基数排序:
又叫桶排序,我们知道可以把一个数字序列分为个、十、百、千、万。。。位,我们把每一个位设置成一个桶,例如有一组无序 数字序列,先将每个数字的个位提取出来,按个位数大小进行排序,再把十位数提取出来,按十位数大小进行排序,直到序列中最高位数排序完毕,得到的序列就为以有序序列。
代码如下
在这里插入代码片
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#define maxsize 100
typedef struct {
int key;
}elemtype;
typedef struct{
elemtype *r;
int length;
}sqlist;
class sort{
public:
void initsqlist(int n,sqlist &L){ //构造长度为n的队列
for(int i=1;i<=n;i++){
scanf("%d",&L.r[i].key);
}
}
int getlensqlist(sqlist &L){ //返回队列的长度
return L.length;
}
void insertsort(sqlist &L){ //插入排序
int i,j;
for(i=2;i<=L.length;i++){ //从第二个元素开始,让他跟前一个元素比较,若小于前一个元素,则应该往前放,若大于则表示他们俩顺序不变
if(L.r[i].key<L.r[i-1].key){ //第i个元素大于第i-1个元素时,从第i-1个元素开始向前遍历比较,若比r【i】 大则继续向前,j--,直到找到比他大的元素位置,记录该点位置未j+1
L.r[0]=L.r[i]; //先把i-1到j+1间的元素向后移一位,再把r【0】 放入第j位置。
for(j=i-1;L.r[j].key>L.r[0].key;j--){ //这里不用考虑j会小于0的情况,因为j=0时,不满足for循环条件,会自动跳出
L.r[j+1]=L.r[j];
}
L.r[j+1]=L.r[0];
}
}
}
void binsertsort(sqlist &L){ //折半排序,与直接插入查找不同的是,在向前找插入位置时,用的是折半查找的方法,
int i,j;
for(i=2;i<=L.length;i++){
if(L.r[i].key<L.r[i-1].key){
L.r[0]=L.r[i];
int low=1,high=i-1;
while(low<=high){
int mid=(low+high)/2;
if(L.r[0].key<L.r[mid].key){
high=mid-1;
}
else{
low=mid+1;
}
}
for(j=i-1;j>=high+1;j--){
L.r[j+1]=L.r[j];
}
L.r[high+1]=L.r[0];
}
}
}
void shellinsert(sqlist &L,int dk){ //希尔排序,其实就是分块的多次直接插入排序,有一个dlta【】数组,保存每次插入排序的间隔,对每个元素进行间隔未dlta【k】 的直接插入排序。
int i,j;
for(i=dk+1;i<=L.length;i++){
if(L.r[i].key<L.r[i-dk].key){
L.r[0]=L.r[i];
for(j=i-dk;j>0 && (L.r[0].key<L.r[j].key);j=j-dk){ //这里向前查找插入位置时,以dk为间隔,当dk=1时,其实就是直接插入排序
L.r[j+dk]=L.r[j];
}
L.r[j+dk]=L.r[0];
}
}
}
void shellsort(sqlist &L,int dlta[],int t) {
for(int k=0;k<t;k++){
shellinsert(L,dlta[k]);
}
}
void Bubble_sort(sqlist &L) {
int i,j,m;
for(int m=1;m<L.length;m++){
for(int j=1;j<=L.length+1;j++){ //向后交换,直到r[j] .key>r[0].key
if(L.r[j].key>L.r[j+1].key){ //若第i个点大于后面的点
L.r[0].key=L.r[j].key; //暂存到r【0】
L.r[j].key =L.r[j+1].key;
L.r[j+1].key=L.r[0].key;
}
//L.r[j-1].key=L.r[0].key; //
}
}
}
int Position(sqlist &L,int low,int high){
L.r[0]=L.r[low];
int poskey=L.r[low].key;
while(low<high){
while(low<high && L.r[high].key>=poskey) high--;
L.r[low]=L.r[high];
while(low < high && L.r[low].key<=poskey) low++;
L.r[high]=L.r[low];
}
L.r[low]=L.r[0];
return low; //返回排序完之后的点的位置
}
void Quick_sort(sqlist &l,int low,int high) { //随机取一个点,将比它小的放左边,比她大的 放右边,对左右两个集合做同样的操作。
if(low<high){ //当low=high时,即low和high相邻时,停止
int mid=Position(l,low,high); // 获取第一个随机点的 位置
Quick_sort(l,low,mid-1); //对该点左边的序列递归调用Quick_sort
Quick_sort(l,mid+1,high); // 对该点右边的序列递归调用Quick_sort
}
}
void Select_sort(sqlist &l) { //选择排序,选择最大的插在末尾
int max=0;
int m=l.length;
for(m;m>=1;m--) {
int flag=0;
for(int i=1;i<=m;i++){
if(l.r[i].key>max){
max=l.r[i].key;
flag=i;
}
}
l.r[0]=l.r[flag]; //暂存最大值
for(flag;flag<=m-1;flag++) {
l.r[flag]=l.r[flag+1];
}
l.r[m]=l.r[0];
}
}
void HeapAdjust(sqlist &l,int s,int m){ //堆排序,调整
int rc=l.r[s].key; //令rc=s对应的根节点
for(int j=2*s;j<m;j*=2){ //从根节点的左孩子开始
if(l.r[j].key<l.r[j+1].key) j++; //找到左右孩子中较大的一个
if(rc>l.r[j].key) break; //若大于r[j] 的值,直接跳出循环
l.r[s] =l.r[j]; //交换两个元素
s=j; //下一次从新位置j开始继续调整,直至交换后的位置为叶子节点
}
l.r[s].key = rc; //把第一个位置的元素存到确定好的位置
}
void Heapsort(sqlist &l) {
int i=0;
int n=l.length; //n为l的长度
for(i=n/2;i>=1;i--){ // 从n/2开始往前构建堆
HeapAdjust(l,i,n); //构建堆函数
}
for(i=n;i>=1;i--){ //输出根节点
printf("%d \t",l.r[1].key);
l.r[1]=l.r[i]; //把最后一个元素与第一个元素交换。
HeapAdjust(l,1,i); //重调整
}
}
/*
void Merge(int R[],int T[],int low,int mid,int high) { //2路归并 ,比较相邻的两个数组,两个指针分别指向数组头,比较大小
int i=low; // 小的存到新数组中,将剩余的直接放到末尾。
int j=mid+1;
int k=low;
while(i<=mid && j<=high){
if(R[i] < T[i]) T[k++]=R[i++];
else T[k++]=R[j++];
}
while(i<mid) T[k++]=R[i++];
while(j<high) T[k++]=R[j++];
}
void Merge_sort(int R[],int T[],int low,int high) { //把给定的序列西安拆分成单个的数组,然后再把相邻的单个数组归并到一起,
if(low==high) T[low]=R[low]; // 归并完把数据存入T中,返回上一层递归再归并。。。
else{
int mid=(low+high)/2;
int S[mid];
Merge_sort(R,S,low,mid);
Merge_sort(R,S,mid+1,high);
Merge(S,T,low,mid,high);
}
}
void Msort(sqlist &L){
int n=L.length;
Merge_sort(L.r,L.r,1,5);
}
*/
int Getmaxlen(sqlist L){
int max=0;
int n=L.length;
int flag=0;
int count=0;
for(int i=1;i<=n;i++){
if(max<L.r[i].key) {
max=L.r[i].key;
flag=i;
}
}
int maxnum=L.r[flag].key;
while(maxnum/10 != 0){
count++;
maxnum/=10;
}
count++;
return count;
}
void Tone(sqlist &L) { //桶排序,将数字拆成个、十、百、千。。位,从个位开始对序列重新排序,再从十位开始排序,直到序列数字最大位数排列完
int n=Getmaxlen(L); //序列中的最大位数
printf("maxlen=:%d\n",n);
int m=L.length;
int T[m+1]; //T数组存放序列的个位、十位数字。
for(int j=1;j<=n;j++){ //循环执行 最大位数次
for(int i=1;i<=m;i++){ //
T[i]=int(L.r[i].key/pow(10,j-1))%10; //从个位开始存进数组中
printf("%d\t",T[i]);
}
printf("\n");
for(int k=L.length;k>=1;k--){ //用简单选择排序,把个位的序列从小到大排好,并对原序列做同样的操作。
int max=0;
int flag=1;
for(int i=k;i>=1;i--){ //这里因为是从小到大排列,在x位值相等的情况下,优先把靠后的值放到末尾,顺序不会出错
if(T[i]>max){
max=T[i];
flag=i;
}
}
if(max!=0){ //只有当max的值不等于0的时候才将其进行对换,等于0时维持原顺序不动。
T[0]=T[flag];
L.r[0]=L.r[flag];
for(flag;flag<=k-1;flag++){
T[flag]=T[flag+1];
L.r[flag]=L.r[flag+1];
}
T[k]=T[0];
L.r[k]=L.r[0];
}
}
}
}
};
int main(){
sort Sort;
sqlist L;
int dlta[5]={5,4,3,2,1};
L.r=(elemtype*)malloc(sizeof(elemtype)*maxsize);
printf("请输入顺序表长度:") ;
scanf("%d",&L.length);
Sort.initsqlist(L.length,L);
printf("r[7]=%d\n",L.r[7].key);
printf("%d\n",Sort.getlensqlist(L));
Sort.Tone(L);
//binsertsort(L);
//shellsort(L,dlta,5);
//Bubble_sort(L);
//Quick_sort(L,1,L.length);
//Select_sort(L);
//Sort.Select_sort(L);
//Sort.Heapsort(L);
//Sort.Merge(L);
for(int i=1;i<=L.length;i++){
printf("%d\t",L.r[i].key);
}
}