您的位置:首页 > 理论基础 > 数据结构算法

算法-排序

2016-12-14 15:53 274 查看

线性表-排序

定义

结构体

直接插入排序

简单交换排序

简单选择排序

1.定义

基于线性表的排序

排序是计算机数据处理的基本操作和重要技术,能有效提高一个数据处理系统的运行效率.

排序设计要的几个要素

1.排序对象.待排序对象,通常是一个线性表

2.排序标准.定序的依据,由数据元素中一个或者一组数据项充当,这些数据项称为排序关键字,简称关键字

3.排序方向.按照关键字递增还是递减排序.

4.排序操作.排序方法和技术,即排序算法或可执行的排序程序.

5.排序结果.已排好序的序列,或称结果序列.

2.结构体

在SequenStruct.c

#include <stdio.h>

#define M 100
typedef struct {
int data[M];
int n;
}SEQUENLIST;


3.直接插入排序

3.1基本思想

直接插入排序的基本思想是,把待排序序列一分为二,前部分为”已排序子序列”,后部分为”待排序子序列”.排序过程即使把”待排序子序列”中的元素一个一个地插入到”已排序子序列”中正确位置上并保证有序,直到”待排序子序列”为空为止.

3.2算法思路

设顺序表S,存储一维数组,长度为n.i,j为整数变量.i标记已排序子序列和待排序子序列的分界点,指向待排序子序列的第1个结点,也就是控制排序是否结束的标记.j用于寻找插入位置时指示已排序子序列范围内的位置,初值为i-1,并且寻找过程中不断减1.在第一个数组元素前增设一个数组元素S[0],称为”哨兵”结点,用于存储当前待插入的结点,以空出该结点原来的位置.因为查找插入位置是从已排序子序列尾部向前进行,所以”哨兵”结点起监视查找终止作用.由于向已排序子序列插入结点时要后移一个结点位置,所以该方法是一边查找一边移动,这样不会造成结点丢失.

3.3算法实现

在Algorithm.h写出方法声明

/*
直接排序算法
*/
SEQUENLIST istSortMethod(SEQUENLIST A);


在Algorithm.c中实现此方法

#include "Algorithm.h"

/*
直接排序算法
*/
SEQUENLIST istSortMethod(SEQUENLIST S){
//1.顺序表中第一个数据为"哨兵",不列入排序的对象
int i,j;
//2.如果顺序表中排序的数据就一个元素,算法结束
if(S.n<=2){
return S;
}
//3.将队列分为"已排序子序列"和"未排序子序列"
//S.data[0]为哨兵,用于存在当前待插入的结点
//已排序子序列:S.data[1],
//待排序子序列:S.data[2]......S.data[S.n];
for(i=2;i<S.n;i++){
//3.1将要排序的数据赋给哨兵
S.data[0]=S.data[i];
//3.2哨兵在已排序子序列查找位置
for(j=i-1;j>0;j--){
//如果哨兵小于已排序子序列元素(从后往前查找),那么把当前位置往后移动一位
if(S.data[0]<=S.data[j]){
S.data[j+1]=S.data[j];
}else{
//如果哨兵和当前比较的大于等于,且终止循环
break;
}

}
//3.3把哨兵放在当前位置的后面,这句话要放在循环的后面,为了防止此时的哨兵是已排序子序列最小的,那么循环直接结束,直接放在了S.data[1]的位置,
S.data[j+1]=S.data[0];
}
//4.将哨兵置为-1
S.data[0]=-1;

printf("直接排序成功succcess!\n");
return S;
}


在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "Algorithm.h"
int main(int argc, const char * argv[]) {
//直接排序算法
printf("直接排序算法\n");
//数据的第一个数据-1,作为哨兵
SEQUENLIST A={{-1,4,6,1,5,9,7,4,6,8,3},11};

printSequenList(A);
A=istSortMethod(A);
printSequenList(A);

}


打印结果:

直接排序算法
sequen={{-1,4,6,1,5,9,7,4,6,8,3},11}
直接排序成功succcess!
sequen={{-1,1,3,4,4,5,6,6,7,8,9},11}
Program ended with exit code: 0


注意:

在创建顺序表的时候,把数据的第一个位置留了出来,作为哨兵,其实要排序的数据是从第二个位置到第n个位置

4.简单交换排序

4.1基本思想

简单交换排序又称冒泡排序.比如:进行从小到大的排序.基本思想:就是把待排序序列分成”已排序子序列”和”未排序子序列”初始时,已排序序列为空.先从待排序子序列(n)中,查找最小的结点然后放到已排序的序列中,然后在从待排序的(n-1)个结点中再次查找出最小的结点,然后放到已排序子序列的后面,这样一直循环,直到待排序序列为最后一个结点,已排序序列的长度为n-1.那么就直接把待排序的序列剩下的最后一个结点就是最大的,不需要比较,直接放到已排序子序列后面.把关键字较小的节点看成”气泡”,每次较小的气泡浮出了水泡,不断的向上”冒”,所以简称”冒泡”排序.

4.2算法思路

设顺序表S,存储为一维数组,长度为n,要求用简单交换排序方法对其进行排序.排序的核心就是结点扫描.扫描就结点序列的循环过程.在扫描中,”最小”结点渐渐漂浮到它的正当位置.为此,用整数变量i来标记扫描完成后最小结点位置;同时也把扫描范围控制到i和n之间,i初始值为1,即表示第1趟扫描,也表示现在要漂浮出的最小结点必须存储在1号结点位置.i的终值是n-1.说明最多要作n-1次扫描,是一个循环.为控制扫描过程,还要设置一个变量j,j从n想i逐1推进,控制扫描过程的结束,对每一次扫描,j的初值总为n.

在排序过程中不断的进行排序,到最后也许一些顺序已经排序好,不会再发生结点的交换,就没有必要再次进行扫描查找,所以增加一个变量k=1;每次进行排序,也判断一下,如果k=1,在进行这一轮的扫描, 此时设置 k=0,在查找最小结点时候,如果发生了结点的交换k=1.如果在进行新一款的扫描查找的时候,如果发现k=0,那么就表示上一轮的扫描没有发生结点的交换,后面的顺序已经是正确的,那么没有比较进行此轮的循环遍历.

4.3算法实现

在Algorithm.h写出方法声明

/*
冒泡排序
*/
SEQUENLIST sisSortMethod(SEQUENLIST A);


在Algorithm.c中实现此方法

#include "Algorithm.h"
SEQUENLIST sisSortMethod(SEQUENLIST S){

//1.判断顺序表的结点数据的数量
if(S.n<2){
return S;
}
int count=0;

int k=1;
//2.查找扫描的次数,即:n-1次,并且k==1,表示前一次发生过结点交换
for(int i=0;i<S.n-1 && k==1 ;i++){
k=0;
count++;
//3.从待排序自序列,从后往前逐1扫描,直到i的位置
for(int j=S.n-1;j>0;j--){
count++;
//3.1比较相邻结点的大小
if(S.data[j]<S.data[j-1]){
//3.2后面结点小于相邻的前一个结点数据,那么就交换
int  temp=S.data[j-1];
S.data[j-1]=S.data[j];
S.data[j]=temp;
//3.3 设置k=1,表示进行了结点的交换
k=1;
}
}
}

printf("冒泡排序成功success! 排序次数:count=%d\n",count);

return S;
}


在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "Algorithm.h"
int main(int argc, const char * argv[]) {
//冒泡排序
printf("冒泡排序\n");
SEQUENLIST S={{88,9,10,7,55,54,98,97,100,99},10};
printSequenList(S);

S=sisSortMethod(S);
printSequenList(S);

}


打印结果:

冒泡排序
sequen={{88,9,10,7,55,54,98,97,100,99},10}
冒泡排序成功success! 排序次数:count=60
sequen={{7,9,10,54,55,88,97,98,99,100},10}


5.简单选择排序

5.1基本思想

简单选择排序的思想是基于简单交换排序.但简单排序有一个很大的缺点,每一次比较都有可能发生两点交换.而简单选择排序在一趟扫描结束后最多只有一次结点交换.显然时间效率比简单交换排序好多了.

设待定排序序列为{R1,R2,….Rn},要求对其进行递增方向的排序.简单选择排序的基本思想是,先对整个待排序序列进行扫描,先找到关键字最小的结点,并与第1个结点交换.称为第1趟扫描.把待排序序列分成了”已排序子序列”和”待排序子序列”两部分.初始时,已排序子序列为空.第二趟扫描对除了第一个结点以外的结点进行扫描,找到次小结点与第2个结点进行交换,已排序子序列增加了一个结点,待排序子序列减少一个结点.如此反复,直到最后一个结点到位,所有结点都进入已排序子序列中,待排序子序列为空.扫描开始时总是把待排序序列的第1个结点假设为最小结点,并记录它的位置号.在扫描过程中,若遇到比他更小的结点时就更换记录新位置号,使扫描完成后记录的位置号是最小结点的位置号.

5.2算法思路

设顺序表S,存储为一维数组,长度为n,要就用简单选择排序方法对其进行排序.这个排序过程的n-1扫描是一个循环,控制每一个”最小”结点的选择.每一次扫描也是一个循环,主要操作是比较,为此,设置整数i,j,k.i控制扫描的循环,初值为1,j控制扫描中的比较,初值值i+1,.k记录最小结点位置号,初值为i.

5.3算法实现

在Algorithm.h写出方法声明

/*
简单选择排序
*/
SEQUENLIST sssSortMethod(SEQUENLIST S);


在Algorithm.c中实现此方法

#include "Algorithm.h"

SEQUENLIST sssSortMethod(SEQUENLIST S){

//1.判断S数据长度
if(S.n<2){
return S;
}
int k;
//2.开始最外层循环
for(int i=0;i<S.n;i++){
//3.使用k记录当前的位置号
k=i;
//4.开始查找数值最小的位置号
for(int j=i+1;j<S.n;j++){
//5.如果当前的位置的数据小于k所在的位置号
if(S.data[j]<S.data[k]){
//6.则把k作为新的位置号
k=j;
}
}
//7.判断k所在的位置号和i所在的位置号是否一样,如果不一样,表示找到了比S.data[i]位置更小的数据
//交换两个节点数据
if(k!=i){
int  temp=S.data[i];
S.data[i]=S.data[k];
S.data[k]=temp;
}
}

printf("简单选择排序成功sucess!\n");
return S;
}


在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "Algorithm.h"
int main(int argc, const char * argv[]) {
//简单选择排序
printf("简单选择排序\n");
SEQUENLIST B={{88,9,10,7,55,54,98,97,100,99},10};
printSequenList(B);

B=sssSortMethod(B);
printSequenList(B);
printf("\n");
}


打印结果:

简单选择排序
sequen={{88,9,10,7,55,54,98,97,100,99},10}
简单选择排序成功sucess!
sequen={{7,9,10,54,55,88,97,98,99,100},10}


这里对简单基本排序算法的一些介绍和实现,直接插入排序,简单插入排序,简单交换排序.三个方法中简单交换排序效率比较高.

源码下载

线性表-排序
定义

结构体

直接插入排序
1基本思想

2算法思路

3算法实现

简单交换排序
1基本思想

2算法思路

3算法实现

简单选择排序
1基本思想

2算法思路

3算法实现
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息