1. 排序
a) 概念:将一组无序的记录按照关键字递增或者递减调整成有序记录(本章记录都为整型数字,关键字为数字值,按照递增排序,待排序的数组都为[70,30,40,10,80,20,90,100,75,60,45])
b) 分类
i. 按涉及的文件内、外存交换排序
[1] 内排序:整个文件放在内存处理,排序时不涉及内、外存交换,适合记录个数不多的小文件
[2] 外排序:排序过程中要进行内、外存交换,适合记录较多的大文件
ii. 按策略划分内部排序
[1] 插入排序:每次将一个待排序的记录按照关键字插入前面已经排好序的子列表中的位置,直到全部记录插入为止
[2] 选择排序:每次从待排序的记录中选中按关键字比较最大或最小的一条记录,顺序放入已排好序的子列表中,直到全部排序完毕
[3] 交换排序:两两比较待排序记录的关键字,发现两个记录的次序相反则交换顺序,直到全部没有反序为止
[4] 归并排序:将两个或者两个以上的有序序列归并成一个序列
[5] 分配排序:无序比较关键字,通过分配和收集实现排序
2. 插入排序
a) 直接插入排序
i. 思想:首先在一个数组中,将下标为0的元素作为有序区域,从下标为1-i的区域依次按顺序取出一个元素插入已排好序的区域中
ii. 代码实现
//直接插入排序
publicstaticint[] insertSort(int []data) {
intlen=data.length;
for(inti=1;i<len;i++) {
inttemp=data[i];
intj;
for(j=i-1;j>=0&&data[j]>temp;j--) {
data[j+1]=data[j];
}
data[j+1]=temp;
}
returndata;
}
iii. 复杂度:顺序表中的记录越接近有序,直接插入算法的时间效率越高,在O(n)-O(n^2)之间,从的来说直接插入排序的时间复杂度为O(n^2)
b) 希尔排序
i. 思想:首先将数组按照一定的增量d分为几个小组,然后对每个小组内部进行直接插入排序,然后使d自减,按照d分成几个小组,在小组内部进行直接插入排序,直到d自减为1,再进行一次直接插入排序。
ii. 代码实现
//希尔排序
public static int[] shellSort(int []data) {
intlen=data.length;
intd=len/3; //增量一般设为待排序数据长度的1/3
for(inti=d;i>0;i--) { //增量从d到1
//下标小于d的元素均是其对应分组内的第一个元素,因此从下标为d开始去到原数组末尾
for(intj=i;j<len;j++) {
inttemp=data[j];
intk;
//将每个元素插入到其对应分组的对应位置
for(k=j-i;k>=0&&data[k]>temp;k=k-i) {
data[k+i]=data[k];
}
data[k+i]=temp;
}
}
returndata;
}
iii. 时间复杂度:取决于分组的增量,大量研究证明,若增量取值合理,时间复杂度为O(n*(logn)^2)
3. 选择排序
a) 直接选择排序
i. 思想:从第一个元素开始和剩下元素进行比较,找到最小的元素和该元素交换位置,直到最后
ii. 代码实现
//直接选择排序
publicstaticint[] selectSort(int []data) {
intlen=data.length;
intindex,temp;
for(inti=0;i<len;i++) {
index=i;
for(intj=i+1;j<len;j++) {
if(data[j]<data[index])
index=j;
}
temp=data[index];
data[index]=data[i];
data[i]=temp;
}
returndata;
}
iii. 时间复杂度:O(n^2)
b) 堆排序
i. 堆的定义:在直接选择排序的基础上借助完全二叉树的结构,将数组的数据放入一棵完全二叉树中,如果这些元素的顺序为,根节点的值都大于其子节点值,则称为最大堆,如果这些元素的顺序为根节点的值均小于其子节点的值,称为最小堆
ii. 堆的性质:最大堆的根节点是数据中最大值,最小堆的根节点是数组中最小值,从根节点到各个叶子节点的路径上的节点都是递减或递增
iii. 思想:先将数组中的所有元素简称堆,然后将根节点输出,然后将剩余n-1个元素构成堆,输出根节点,直到只有一个元素
iv. 构建最大堆
[1] 根据完全二叉树的性质,最后一个叶节点对应的父节点在数组中的下标为i=(n)/2-1,因此从次下标开始一直到下标为0为止,比较下标为i,2i+1,2i+2的元素大小,将最大值与下标为i的元素交换位置
[2] 如果经过[1]使第i个根节点的子节点作为根节点的树不满足最大堆,则再次堆其子节点作为根节点的子树进行交换
v. 代码实现
//堆排序算法
//构建最大堆
publicvoid static createHeap(int []data,intmin,intmax) {
inttemp;
intj;
intk;
for(inti=(max/2-1);i>=0;i--) {
j=i;
for(k=j*2+1;k<max;k=2*k+1) {
temp=data[j];
if(data[k]<data[k+1])
k++;
if(temp<data[k]) {
data[j]=data[k];
data[k]=temp;
j=k;
}
}
}
}
//构建堆排序
public static int[] heapSort(int []data) {
intlen=data.length;
inttemp;
for(inti=len-1;i>0;i--) {
createHeap(data, 0, i);
temp=data[i];
data[i]=data[0];
data[0]=temp;
}
returndata;
}
vi. 时间复杂度:O(nlogn)
4. 交换排序
a) 冒泡排序
i. 思想:按照序号从下标为0的元素开始依次与自己相邻的元素比较,满足条件则交换位置,一直到最后一个元素,然后对除最后一个元素的所有元素再进行冒泡,直到所有元素都排好序。
ii. 代码实现
//冒泡排序
publicstaticint[] bubbleSort(int []data) {
intlen=data.length;
for(inti=0;i<len-1;i++) {
for(intj=0;j<len-1-i;j++) {
inttemp=data[j];
if(data[j]>data[j+1]) {
data[j]=data[j+1];
data[j+1]=temp;
}
}
}
returndata;
}
iii. 时间复杂度:O(n^2)
b) 快速排序
i. 思想:首先取待排序的数组第一个元素为基准值,分别从数组第一个元素和最后一个元素开始扫描,从左向右扫描的序号为i,从右向左的扫描序号为j,当j=i时停止搜索,将基准值和坐标为i=j的元素交换,然后从这个元素分成两个数组,继续进行排序,直到全部数组分组后只有一个元素
ii. 代码实现
//快速排序
publicstaticvoid quickSort(intdata[],intstart,intend) {
intpivot=data[start];
inti=start+1;
intj=end;
inttemp;
intindex;
//要找到一个位置,在这个位置以前所有数都小于他,在这个数以后所有数都大于他
while(i<j) {
if(data[i]<pivot)
i++;
if(data[j]>pivot&&j>i)//注意:要加i<j,因为有时候经过这一轮会i>j
j--;
if(data[i]>pivot&&data[j]<pivot) {
temp=data[i];
data[i]=data[j];
data[j]=temp;
}
}
temp=data[start];
if(temp>data[i])
index=j;
else
index=j-1;
data[start]=data[index];
data[index]=temp;
if((index-1-start)>=1)
quickSort(data, start, index-1);
if((end-index-1)>=1)
quickSort(data, index+1, end);
}
iii. 时间复杂度:O(n*logn)
5. 归并排序
a) 二路归并排序思想:首先将具有n个数据的数组看作n个数组,然后将相邻两个数组归并成一个数组并排序,继续归并,直到只有一个数组
b) 时间复杂度:O(n*logn)
c) 空间复杂度:O(n)
6. 基数排序
a) 思想:按待排序关键字的组成成分进行排序,依次按照各个记录的关键字的位的值进行比较,直到比较完所有的位。(对于整数组成的数组来讲,首先按照个位数字的大小比较,然后按照十位数字大小比较,最后按照百位数字大小比较,直到所有位数都比较完)
b) 时间复杂度:O(d(n+radix)),d是关键码,radix是关键码的取值范围
1. 排序
a) 概念:将一组无序的记录按照关键字递增或者递减调整成有序记录(本章记录都为整型数字,关键字为数字值,按照递增排序,待排序的数组都为[70,30,40,10,80,20,90,100,75,60,45])
b) 分类
i. 按涉及的文件内、外存交换排序
[1] 内排序:整个文件放在内存处理,排序时不涉及内、外存交换,适合记录个数不多的小文件
[2] 外排序:排序过程中要进行内、外存交换,适合记录较多的大文件
ii. 按策略划分内部排序
[1] 插入排序:每次将一个待排序的记录按照关键字插入前面已经排好序的子列表中的位置,直到全部记录插入为止
[2] 选择排序:每次从待排序的记录中选中按关键字比较最大或最小的一条记录,顺序放入已排好序的子列表中,直到全部排序完毕
[3] 交换排序:两两比较待排序记录的关键字,发现两个记录的次序相反则交换顺序,直到全部没有反序为止
[4] 归并排序:将两个或者两个以上的有序序列归并成一个序列
[5] 分配排序:无序比较关键字,通过分配和收集实现排序
2. 插入排序
a) 直接插入排序
i. 思想:首先在一个数组中,将下标为0的元素作为有序区域,从下标为1-i的区域依次按顺序取出一个元素插入已排好序的区域中
ii. 代码实现
//直接插入排序
publicstaticint[] insertSort(int []data) {
intlen=data.length;
for(inti=1;i<len;i++) {
inttemp=data[i];
intj;
for(j=i-1;j>=0&&data[j]>temp;j--) {
data[j+1]=data[j];
}
data[j+1]=temp;
}
returndata;
}
iii. 复杂度:顺序表中的记录越接近有序,直接插入算法的时间效率越高,在O(n)-O(n^2)之间,从的来说直接插入排序的时间复杂度为O(n^2)
b) 希尔排序
i. 思想:首先将数组按照一定的增量d分为几个小组,然后对每个小组内部进行直接插入排序,然后使d自减,按照d分成几个小组,在小组内部进行直接插入排序,直到d自减为1,再进行一次直接插入排序。
ii. 代码实现
//希尔排序
public static int[] shellSort(int []data) {
intlen=data.length;
intd=len/3; //增量一般设为待排序数据长度的1/3
for(inti=d;i>0;i--) { //增量从d到1
//下标小于d的元素均是其对应分组内的第一个元素,因此从下标为d开始去到原数组末尾
for(intj=i;j<len;j++) {
inttemp=data[j];
intk;
//将每个元素插入到其对应分组的对应位置
for(k=j-i;k>=0&&data[k]>temp;k=k-i) {
data[k+i]=data[k];
}
data[k+i]=temp;
}
}
returndata;
}
iii. 时间复杂度:取决于分组的增量,大量研究证明,若增量取值合理,时间复杂度为O(n*(logn)^2)
3. 选择排序
a) 直接选择排序
i. 思想:从第一个元素开始和剩下元素进行比较,找到最小的元素和该元素交换位置,直到最后
ii. 代码实现
//直接选择排序
publicstaticint[] selectSort(int []data) {
intlen=data.length;
intindex,temp;
for(inti=0;i<len;i++) {
index=i;
for(intj=i+1;j<len;j++) {
if(data[j]<data[index])
index=j;
}
temp=data[index];
data[index]=data[i];
data[i]=temp;
}
returndata;
}
iii. 时间复杂度:O(n^2)
b) 堆排序
i. 堆的定义:在直接选择排序的基础上借助完全二叉树的结构,将数组的数据放入一棵完全二叉树中,如果这些元素的顺序为,根节点的值都大于其子节点值,则称为最大堆,如果这些元素的顺序为根节点的值均小于其子节点的值,称为最小堆
ii. 堆的性质:最大堆的根节点是数据中最大值,最小堆的根节点是数组中最小值,从根节点到各个叶子节点的路径上的节点都是递减或递增
iii. 思想:先将数组中的所有元素简称堆,然后将根节点输出,然后将剩余n-1个元素构成堆,输出根节点,直到只有一个元素
iv. 构建最大堆
[1] 根据完全二叉树的性质,最后一个叶节点对应的父节点在数组中的下标为i=(n)/2-1,因此从次下标开始一直到下标为0为止,比较下标为i,2i+1,2i+2的元素大小,将最大值与下标为i的元素交换位置
[2] 如果经过[1]使第i个根节点的子节点作为根节点的树不满足最大堆,则再次堆其子节点作为根节点的子树进行交换
v. 代码实现
//堆排序算法
//构建最大堆
publicvoid static createHeap(int []data,intmin,intmax) {
inttemp;
intj;
intk;
for(inti=(max/2-1);i>=0;i--) {
j=i;
for(k=j*2+1;k<max;k=2*k+1) {
temp=data[j];
if(data[k]<data[k+1])
k++;
if(temp<data[k]) {
data[j]=data[k];
data[k]=temp;
j=k;
}
}
}
}
//构建堆排序
public static int[] heapSort(int []data) {
intlen=data.length;
inttemp;
for(inti=len-1;i>0;i--) {
createHeap(data, 0, i);
temp=data[i];
data[i]=data[0];
data[0]=temp;
}
returndata;
}
vi. 时间复杂度:O(nlogn)
4. 交换排序
a) 冒泡排序
i. 思想:按照序号从下标为0的元素开始依次与自己相邻的元素比较,满足条件则交换位置,一直到最后一个元素,然后对除最后一个元素的所有元素再进行冒泡,直到所有元素都排好序。
ii. 代码实现
//冒泡排序
publicstaticint[] bubbleSort(int []data) {
intlen=data.length;
for(inti=0;i<len-1;i++) {
for(intj=0;j<len-1-i;j++) {
inttemp=data[j];
if(data[j]>data[j+1]) {
data[j]=data[j+1];
data[j+1]=temp;
}
}
}
returndata;
}
iii. 时间复杂度:O(n^2)
b) 快速排序
i. 思想:首先取待排序的数组第一个元素为基准值,分别从数组第一个元素和最后一个元素开始扫描,从左向右扫描的序号为i,从右向左的扫描序号为j,当j=i时停止搜索,将基准值和坐标为i=j的元素交换,然后从这个元素分成两个数组,继续进行排序,直到全部数组分组后只有一个元素
ii. 代码实现
//快速排序
publicstaticvoid quickSort(intdata[],intstart,intend) {
intpivot=data[start];
inti=start+1;
intj=end;
inttemp;
intindex;
//要找到一个位置,在这个位置以前所有数都小于他,在这个数以后所有数都大于他
while(i<j) {
if(data[i]<pivot)
i++;
if(data[j]>pivot&&j>i)//注意:要加i<j,因为有时候经过这一轮会i>j
j--;
if(data[i]>pivot&&data[j]<pivot) {
temp=data[i];
data[i]=data[j];
data[j]=temp;
}
}
temp=data[start];
if(temp>data[i])
index=j;
else
index=j-1;
data[start]=data[index];
data[index]=temp;
if((index-1-start)>=1)
quickSort(data, start, index-1);
if((end-index-1)>=1)
quickSort(data, index+1, end);
}
iii. 时间复杂度:O(n*logn)
5. 归并排序
a) 二路归并排序思想:首先将具有n个数据的数组看作n个数组,然后将相邻两个数组归并成一个数组并排序,继续归并,直到只有一个数组
b) 时间复杂度:O(n*logn)
c) 空间复杂度:O(n)
6. 基数排序
a) 思想:按待排序关键字的组成成分进行排序,依次按照各个记录的关键字的位的值进行比较,直到比较完所有的位。(对于整数组成的数组来讲,首先按照个位数字的大小比较,然后按照十位数字大小比较,最后按照百位数字大小比较,直到所有位数都比较完)
b) 时间复杂度:O(d(n+radix)),d是关键码,radix是关键码的取值范围