排序过程中用到的一些公用方法
public static void swap(int[] data, int i, int j){//交换
if (i == j) {
return;
}
data[i] = data[i] + data[j];
data[j] = data[i] - data[j];
data[i] = data[i] - data[j];
}
public static void print(int[] data) {//打印数组
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
public static void main(String[] args) {
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 ,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7};
print(data);
// heapSort(data);
// selectSort(data);
// bubbleSort(data);
quickSort(data,0,data.length-1);
// insertSort(data);
// bInsertSort(data);
// bucketSort(data, 0, 10);
System.out.println("排序后的数组为:");
print(data);
}
if (i == j) {
return;
}
data[i] = data[i] + data[j];
data[j] = data[i] - data[j];
data[i] = data[i] - data[j];
}
public static void print(int[] data) {//打印数组
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
public static void main(String[] args) {
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 ,7,7,7,7,7,7,7,7,7,7 ,7,7,7,7,7,7,7};
print(data);
// heapSort(data);
// selectSort(data);
// bubbleSort(data);
quickSort(data,0,data.length-1);
// insertSort(data);
// bInsertSort(data);
// bucketSort(data, 0, 10);
System.out.println("排序后的数组为:");
print(data);
}
一、堆排序
//堆排序
//空间复杂度为O(1), 最坏时间复杂度为O(nlog2n)
public static void heapSort(int[] data) {
for (int i = 0; i < data.length; i++) {
createMaxdHeap(data, data.length - 1 - i);
swap(data, 0, data.length - 1 - i);
}
}
//构建堆
public static void createMaxdHeap(int[] data, int lastIndex) {
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
// 保存当前正在判断的节点
int k = i;
// 若当前节点的子节点存在
while (2 * k + 1 <= lastIndex) {
// biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点
int biggerIndex = 2 * k + 1;
if (biggerIndex < lastIndex) {
// 若右子节点存在,否则此时biggerIndex应该等于 lastIndex
if (data[biggerIndex] < data[biggerIndex + 1]) {
// 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值
biggerIndex++;
}
}
if (data[k] < data[biggerIndex]) {
// 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k
swap(data, k, biggerIndex);
k = biggerIndex;
} else {
break;
}
}
}
}
//空间复杂度为O(1), 最坏时间复杂度为O(nlog2n)
public static void heapSort(int[] data) {
for (int i = 0; i < data.length; i++) {
createMaxdHeap(data, data.length - 1 - i);
swap(data, 0, data.length - 1 - i);
}
}
//构建堆
public static void createMaxdHeap(int[] data, int lastIndex) {
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
// 保存当前正在判断的节点
int k = i;
// 若当前节点的子节点存在
while (2 * k + 1 <= lastIndex) {
// biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点
int biggerIndex = 2 * k + 1;
if (biggerIndex < lastIndex) {
// 若右子节点存在,否则此时biggerIndex应该等于 lastIndex
if (data[biggerIndex] < data[biggerIndex + 1]) {
// 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值
biggerIndex++;
}
}
if (data[k] < data[biggerIndex]) {
// 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k
swap(data, k, biggerIndex);
k = biggerIndex;
} else {
break;
}
}
}
}
二、直接选择排序
//直接选择排序
//直接选择排序排序时间复杂度下界为O(nlogn),最坏情况为O(n^2)
//空间复杂度O(1)
public static void selectSort(int[] data){
for (int i = 0; i < data.length; i++) {
int minIndex =i;
for (int j = i; j < data.length; j++) {
if (data[j]<data[minIndex]) {// 若后面的元素值小于最小值,将j赋值给minIndex
minIndex = j;
}
}
if (minIndex != i) {
swap(data, i, minIndex);
}
}
}
三、冒泡排序
//冒泡排序
//时间复杂度为O(n^2) 稳定性
//O(1)的额外的空间
public static void bubbleSort(int[] data) {
for (int i = 0; i < data.length-1; i++) {
for (int j = 0; j < data.length-i-1; j++) {
if (data[j] > data[j + 1]) {
swap(data, j, j + 1);
}
}
}
}
//时间复杂度为O(n^2) 稳定性
//O(1)的额外的空间
public static void bubbleSort(int[] data) {
for (int i = 0; i < data.length-1; i++) {
for (int j = 0; j < data.length-i-1; j++) {
if (data[j] > data[j + 1]) {
swap(data, j, j + 1);
}
}
}
}
四、快速排序
//从待排的数据序列中任取一个数据(如第一个数据)作为分界值,所有比它小的数据元素放到左边,所有比它大的数据元素放到它的右边
//时间复杂度 最好情况(每次总是选到中间值作枢轴)T(n)=O(nlogn)最坏情况(每次总是选到最小或最大元素作枢轴)
//做n-1趟,每趟比较n-i次,总的比较次数最大:[O(n²)]
//平均时间复杂度为::T(n)=O(nlogn)
public static int Partititon(int[] data, int low , int high){
//交换data中[low....high]的值,参考数值记录到位,并返回其所在位置,此时
//在他之前的记录均小于等于他
int key = data[low];
while(low<high){
while(low<high && data[high]>=key){
high--;
}
data[low] = data[high];
while (low<high && data[low]<=key) {
low++;
}
data[high]=data[low];
}
data[low]=key;
return low;
}
public static void quickSort(int[] data, int low, int high) {
if (low<high) {
int p = Partititon(data, low, high);
quickSort(data, low, p-1);//对左边的进行递归排序
quickSort(data, p+1, high);//对右边的进行递归排序
}
}
//时间复杂度 最好情况(每次总是选到中间值作枢轴)T(n)=O(nlogn)最坏情况(每次总是选到最小或最大元素作枢轴)
//做n-1趟,每趟比较n-i次,总的比较次数最大:[O(n²)]
//平均时间复杂度为::T(n)=O(nlogn)
public static int Partititon(int[] data, int low , int high){
//交换data中[low....high]的值,参考数值记录到位,并返回其所在位置,此时
//在他之前的记录均小于等于他
int key = data[low];
while(low<high){
while(low<high && data[high]>=key){
high--;
}
data[low] = data[high];
while (low<high && data[low]<=key) {
low++;
}
data[high]=data[low];
}
data[low]=key;
return low;
}
public static void quickSort(int[] data, int low, int high) {
if (low<high) {
int p = Partititon(data, low, high);
quickSort(data, low, p-1);//对左边的进行递归排序
quickSort(data, p+1, high);//对右边的进行递归排序
}
}
五、直接插入排序
//直接插入排序 基本操作就是将待排序的数据元素按其关键字值的大小插入到前面的有序序列中。
//时间复杂度为O(n^2) 空间复杂度为O(1)
public static void insertSort(int[] data) {
for (int i = 1; i < data.length; i++) {
for (int j = i; (j > 0) && (data[j] < data[j - 1]); j--) {
swap(data, j, j - 1);
print(data);
}
}
}
//时间复杂度为O(n^2) 空间复杂度为O(1)
public static void insertSort(int[] data) {
for (int i = 1; i < data.length; i++) {
for (int j = i; (j > 0) && (data[j] < data[j - 1]); j--) {
swap(data, j, j - 1);
print(data);
}
}
}
六、希尔排序
//希尔排序对直接插入排序进行了简单的改进:它通过加大插入排序中元素之间的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项大跨度地移动
public static void shellSortC(int[] data){
int h = 1;
while (h <= data.length / 3) {
h = h * 3 + 1;
}
while (h > 0) {
for (int i = h; i < data.length; i += h) {
for (int j = i; (j>0) && (data[j] < data[j-h]); j -=h) {
swap(data, j, j-h);
print(data);
}
}
// 计算出下一个h值
h = (h - 1) / 3;
}
}
七、插入排序
//插入排序
public static void insertSort1(int[] data) {
for (int i = 1; i < data.length; i++) {
// 缓存i处的元素值
int tmp = data[i];
if (data[i] < data[i - 1]) {
int j = i - 1;
// 整体后移一格
while (j >= 0 && data[j] > tmp) {
data[j + 1] = data[j];
j--;
}
// 最后将tmp插入合适的位置
data[j + 1] = tmp;
print(data);
}
}
}
public static void insertSort1(int[] data) {
for (int i = 1; i < data.length; i++) {
// 缓存i处的元素值
int tmp = data[i];
if (data[i] < data[i - 1]) {
int j = i - 1;
// 整体后移一格
while (j >= 0 && data[j] > tmp) {
data[j + 1] = data[j];
j--;
}
// 最后将tmp插入合适的位置
data[j + 1] = tmp;
print(data);
}
}
}
八、折半插入排序
//折半插入排序 又称二分插入排序法,是直接插入排序法的改良版,也需要执行i-1趟插入,
//不同之处在于,第i趟插入,先找出第i+1个元素应该插入的的位置,假定前i个数据是已经处于有序状态。
public static void bInsertSort(int[] data) {
int length = data.length;
for (int i = 1; i < length; i++) {
int tempVal = data[i];
int low = 0;
int high = i - 1;
while (low <= high) {
int middle = (low + high) / 2;
if (tempVal < data[middle]){
high = middle - 1;
}else{
low = middle + 1;
}
}
for (int j = i; j > high + 1; j--){
data[j] = data[j - 1];//记录后移
}
data[high + 1] = tempVal;//插入
}
}
//不同之处在于,第i趟插入,先找出第i+1个元素应该插入的的位置,假定前i个数据是已经处于有序状态。
public static void bInsertSort(int[] data) {
int length = data.length;
for (int i = 1; i < length; i++) {
int tempVal = data[i];
int low = 0;
int high = i - 1;
while (low <= high) {
int middle = (low + high) / 2;
if (tempVal < data[middle]){
high = middle - 1;
}else{
low = middle + 1;
}
}
for (int j = i; j > high + 1; j--){
data[j] = data[j - 1];//记录后移
}
data[high + 1] = tempVal;//插入
}
}
九、桶式排序
//桶式排序
public static void bucketSort(int[] data, int min, int max) {
// 缓存数组
int[] tmp = new int[data.length];
// buckets用于记录待排序元素的信息
// buckets数组定义了max-min个桶
int[] buckets = new int[max - min];
// 计算每个元素在序列出现的次数
for (int i = 0; i < data.length; i++) {
buckets[data[i] - min]++;
}
// 计算“落入”各桶内的元素在有序序列中的位置
for (int i = 1; i < max - min; i++) {
buckets[i] = buckets[i] + buckets[i - 1];
}
// 将data中的元素完全复制到tmp数组中
System.arraycopy(data, 0, tmp, 0, data.length);
// 根据buckets数组中的信息将待排序列的各元素放入相应位置
for (int k = data.length - 1; k >= 0; k--) {
data[--buckets[tmp[k] - min]] = tmp[k];
}
}
public static void bucketSort(int[] data, int min, int max) {
// 缓存数组
int[] tmp = new int[data.length];
// buckets用于记录待排序元素的信息
// buckets数组定义了max-min个桶
int[] buckets = new int[max - min];
// 计算每个元素在序列出现的次数
for (int i = 0; i < data.length; i++) {
buckets[data[i] - min]++;
}
// 计算“落入”各桶内的元素在有序序列中的位置
for (int i = 1; i < max - min; i++) {
buckets[i] = buckets[i] + buckets[i - 1];
}
// 将data中的元素完全复制到tmp数组中
System.arraycopy(data, 0, tmp, 0, data.length);
// 根据buckets数组中的信息将待排序列的各元素放入相应位置
for (int k = data.length - 1; k >= 0; k--) {
data[--buckets[tmp[k] - min]] = tmp[k];
}
}