1. 快速排序:
方法:快速排序就是先选中一个基准数,然后把比这个基准数小的数字移到基准数的左边,比基准数大的移到右边。
**特点**:
- 快排的运行时间依赖于划分是否平衡,而平衡与否又依赖于用户划分的主元素。
- 如果划分是平衡的,那么快速排序算法性能与归并排序一样。
- 如果划分时不平衡的,那么快速排序的性能就接近于插入排序了
我们用来避免最差情况发生的方法如下:
**求序列的中值**,然后选取序列的中值作为轴元素
#中轴居中法:
void quick_sort(int[] nums,int l,int r){//快速排序,l排序起始位置,r排序结束位置
if(l>=r) return;
int i=l-1,j=r+1;//为了在边界时满足循环判断条件
int x=nums[(r-l)/2+l];//x是轴,轴是一个值,最终位置不定
while(i<j){
do i++;while(nums[i]<x);
do j--;while(nums[j]>x);
if(i<j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
}
quick_sort(nums,l,j);//中轴要落到j位置但是不一定落到j所以要再排序j
quick_sort(nums,j+1,r);//j右边一定是比中轴大数
}
#最左边是初始轴法(填坑法)
void quick_sort(int[] nums,int l,int r){//快速排序,l排序起始位置,r排序结束位置
if(l>=r) return;
int i=l,j=r;
int x=nums[i];//x是轴,轴是一个值,最终位置不定(起初l是坑)
while(i<j){
while(i<j&&nums[j]>=x){
j--;
}
nums[i]=nums[j];//填坑
while(i<j&&nums[i]<=x){
i++;
}
nums[j]=nums[i];
}
nums[i]=x;//轴归位
quick_sort(nums,l,j-1);//中轴要落到j位置但是不一定落到j所以要再排序j
quick_sort(nums,j+1,r);//j右边一定是比中轴大数
}
2. 冒泡排序
方法:首先从数组的第一个元素开始到数组最后一个元素为止,对数组中相邻的两个元素进行比较,如果位于数组左端的元素大于数组右端的元素,则交换这两个元素在数组中的位置。这样操作后数组最右端的元素即为该数组中所有元素的最大值。接着对该数组除最右端的n-1个元素进行同样的操作,再接着对剩下的n-2个元素做同样的操作,直到整个数组有序排列。
时间复杂度:O(n)或O(n^2)
/* 冒泡排序 */
void BubbleSort(int[] arr, int length){
for (int i = 0; i < length; i++){
for (int j = 0; j < length - i - 1; j++){
if (arr[j] > arr[j + 1]){
int temp= arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
}
3. 选择排序
定义:每一趟选择一个最小的值,交换到指定位置
时间复杂度:O(n^2)
/* 选择排序 */
void SelectionSort(int[] arr){
int index, temp,length=arr.length;
for (int i = 0; i < length; i++){
index = i;//最小值位置
for (int j = i + 1; j < length; j++){
if (arr[j] < arr[index])
index = j;
}
if (index != i){//位置交换
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
}
}
4. 堆排序
#建堆,将堆转换为有序数组
public static void heapSort(int[] arr) {
int temp=0;
for(int i=arr.length/2-1;i>=0;i--){//构建好大根堆
adjustHeap(arr,i,arr.length);
}
for(int j=arr.length-1;j>0;j--){//由大根堆变成排序好的数组
temp=arr[j];
arr[j]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,j);
}
}
#调整以i为根的树为大根堆
public static void adjustHeap(int[] arr,int i,int length) {
int temp=arr[i];//先取出当前元素的值,保存在临时变量
for(int k=i*2+1;k<length;k=k*2+1) {//开始调整
if(k+1<length && arr[k]<arr[k+1]) k++;//说明左子结点的值小于右子结点的值
if(arr[k]>temp) {//如果子结点大于父结点
arr[i]=arr[k];//把较大的值赋给当前结点
i=k;//i指向k,继续循环比较
}else break;
}
//当for 循环结束后我们已经将以i为父结点的树的最大值,放在了最顶(局部)
arr[i]=temp;//将temp值放到调整后的位置
}
5. 希尔排序
定义:先将待排记录序列分割成为若干子序列分别进行插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行一次直接插入排序。
时间复杂度:n^(1.3—2))
void ShellSort(int[] arr){
int len=arr.length,length=len;
do{// 确定分组的增量
len = len / 3 + 1;
for (int i = 0; i < len; i++){
for (int j = i + len; j < length; j += len){
if (arr[j] < arr[j - len]){
int temp = arr[j],k;
for (k = j - len; k >= 0 && temp < arr[k]; k -= len){
arr[k + len] = arr[k];
}
arr[k + len] = temp;
}
}
}
} while (len > 1);
}
6. 折半插入排序
//折半插入排序
public static void binaryInsertSort(int[] data){
for(int i=1;i<data.length;i++){
if(data[i] < data[i-1]){
int tmp = data[i];//缓存i处的元素值
int low = 0;//记录搜索范围的左边界
int high = i-1;
while(low <= high){
int mid = (low+high)/2;//记录中间位置
if(data[mid] < tmp){//比较中间位置数据和i处数据大小,以缩小搜索范围
low = mid +1;
}else
high = mid - 1;
}
for(int j = i;j>low;j--)//将low---i处的数据整体向后移动1位
data[j] = data[j-1];
data[low] = tmp;
}
}
}
7.归并排序
分治策略(将问题分成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
时间复杂度:O(nlogn)
空间复杂度:O(n)
public ListNode sortList(ListNode head, ListNode tail) {//待排链表的头结点与尾节点
if (head == null)
return head;
if (head.next == tail) {//如果只有两个节点,尾节点由另一个负责
head.next = null;
return head;
}
ListNode slow = head, fast = head;
while (fast != tail) {//找到中间节点
slow = slow.next;
fast = fast.next;
if (fast != tail)
fast = fast.next;
}
ListNode mid = slow;
ListNode list1 = sortList(head, mid);
ListNode list2 = sortList(mid, tail);
ListNode sorted = merge(list1, list2);
return sorted;
}
public ListNode merge(ListNode head1, ListNode head2) {
ListNode tHead = new ListNode(0);
ListNode temp = tHead, temp1 = head1, temp2 = head2;
while (temp1 != null && temp2 != null) {
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
if (temp1 != null) {
temp.next = temp1;
} else if (temp2 != null)
temp.next = temp2;
return tHead.next;
}
8.基数排序
//基数排序
public static void radixSort(int[] arr) {
int max=0;//得到数组中的最大数的小标,这样才能知道要循环多少轮
for(int i=1;i<arr.length;i++) {
if(arr[max]<arr[i]) {
max=i;
}
}
int times=(arr[max]+"").length();//得到数字共有几位数
for(int time=0,n=1;time<times;time++,n*=10) {
//创建桶,共有10个桶,每个桶最多有arr.length个数据
int[][] bucket=new int[10][arr.length];
//用于记录每个桶中有多少数据,用于遍历桶中的数据
int[] bECount=new int[10];
//开始遍历数组
for(int i=0;i<arr.length;i++) {
int digitOfElement=(int) ((arr[i]/n)%10); //取出对应的位数
//将其存入bucket中
bucket[digitOfElement][bECount[digitOfElement]]=arr[i];
bECount[digitOfElement]++;
}
//将bucket中的数据输出到arr中
int index=0;
for(int i=0;i<bECount.length;i++) {
if(bECount[i]!=0) {
for(int j=0;j<bECount[i];j++) {
arr[index]=bucket[i][j];
index++;
}
}
}
}
}