#include<iostream>
using namespace std;
void out(int *arr,int len) {
for(int i=0; i<len; i++) {
printf("%d ",arr[i]);
}
printf("\n");
}
//簡單排序:選擇、冒泡、直接插入
/*
選擇排序:從無序區選擇一個最值放進有序區。
*/
void choice(int *arr,int len) {
for(int i=0; i<len-1; i++) {
int min=arr[i];
int k=i;
for(int j=i+1; j<len; j++) {
if(arr[j]<min) {
min=arr[j];
k=j;
}
}
if(k!=i) {
int temp=arr[k];
arr[k]=arr[i];
arr[i]=temp;
}
}
}
/*
冒泡排序:動態排序,每一趟經過比較得到一個最值
*/
void bubble(int *arr,int len) {
for(int i=0; i<len-1; i++) {
for(int j=0; j<len-i-1; j++) {
if(arr[j]>arr[j+1]) {
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
//直接插入排序:從原序列中逐一拿來建序;從端部一直比較,得到插入位置
void direct_insert(int *arr,int len) {
if(len<1)return;
for(int i=1; i<len; i++) {
if(arr[i]<arr[i-1]) {
int j=i-1;
while(j>=0) {
if(arr[i]>=arr[j]) {
break;
}
j--;
}
int temp=arr[i];
for(int k=i-1; k>=j+1; k--) {
arr[k+1]=arr[k];
}
arr[j+1]=temp;
}
}
}
/*
希爾排序(直接插入排序的改進):間隔gap分組,直到gap=1;對每個分組進行直接插入排序;
*/
void shell(int *arr,int len,int gap,int dgap) {
if(len<1||gap>len||gap<1||dgap>gap) {
printf("參數錯誤!\n");
return;//條件
}
while(gap>=1) { //gap逐漸減小到1,分爲gap組
for(int i=0; i<gap; i++) {
//對每一組進行直接插入排序
for(int j=i; j<len; j=j+gap) {
int t=arr[j];
for(int k=j-gap; k>=0; k=k-gap) {
if(t>=arr[k])break;
int temp=arr[k+gap];
arr[k+gap]=arr[k];
arr[k]=temp;
}
}
}
gap=gap/dgap;
}
}
/*
快排(冒泡排序的改進):遞歸寫法。
一趟排序:選擇分組的第一個元素作爲標杆key,從後往前與 key比較和從前往後與key比較,將
分成左邊小於key的部分和key右邊大於 key的部分。
算法:注意臨界數據
*/
void swap(int *arr,int v1,int v2) {
int temp=arr[v1];
arr[v1]=arr[v2];
arr[v2]=temp;
}
void quick(int *arr,int l,int r) {
if(l>=r)return;
int key=arr[l];
int i=l;
int j=r;
while(i!=j) {
while(arr[j]>=key&&j>i) {
j--;
}
swap(arr,i,j);
while(arr[i]<=key&&j>i) {
i++;
}
swap(arr,i,j);
}
quick(arr,l,i-1);
quick(arr,i+1,r);
}
//快排的遞推寫法
void quick2(int *arr,int l,int r) {
}
/*
堆排序算法(選擇排序的改進):主要實現在結點下滑算法 。
1. 初始堆(這裏建成最大堆)
將數組元素邏輯上構造成完全二叉樹,在從非葉結點到根結點依次執行下滑。
2. 調整堆
將根結點和最後一個無序區葉結點交換,然後將交換後的葉結點歸爲有序區,直到有序區的個數爲n-1;
*/
void glidedown(int *arr,int len,int index) {
if(index>=len)return;
if(index*2+1<len) { //有左海子
if(index*2+2<len) { //並且有右孩子
if(arr[index*2+1]<arr[index*2+2]) { //下滑到最大的那個孩子
if(arr[index]<arr[index*2+2]) {
swap(arr,index,index*2+2);
glidedown(arr,len,index*2+2);
}
} else {
if(arr[index]<arr[index*2+1]) {
swap(arr,index,index*2+1);
glidedown(arr,len,index*2+1);
}
}
} else { //有左海子,沒有右孩子
if(arr[index]<arr[index*2+1]) {
swap(arr,index,index*2+1);
glidedown(arr,len,index*2+1);
}
}
}
}
void heap(int *arr,int len) {
//最後一個非葉結點下標
int ny_index=(len-1-1)/2;
//1. 造初始堆
for(int i=ny_index; i>=0; i--) {
glidedown(arr,len,i);
}
printf("初始堆:\n");
out(arr,len);
//2. 調整堆(從最後一個無序區結點開始調整,調整n-1次)
int count=0;
for(int j=len-1; j>=1; j--) {
swap(arr,0,j);
count++;
int ny_index2=(j-1)/2;
for(int k=ny_index2; k>=0; k--) {
glidedown(arr,len-count,k);
}
}
}
/*
歸併排序:採用分治法。
將兩個有序的數列合併爲一個有序數列
合併算法:1. 有一個存放有序序列的空間
2. 兩個指針分別指向兩個有序數列起始位置
3. 將指針所比較的最值放進有序空間,指針移動
上面的2,3再循環完成兩序列的合併
*/
void merge_two(int *arr,int *temp,int start,int mid,int end){
int i=start;
int j=mid+1;
int k=0;
while(i<=mid&&j<=end){
if(arr[i]<arr[j]){
temp[k++]=arr[i++];
}else{
temp[k++]=arr[j++];
}
}
while(i<=mid){
temp[k++]=arr[i++];
}
while(j<=end){
temp[k++]=arr[j++];
}
//注意這裏
for(int h=0;h<k;h++){
arr[start++]=temp[h];
}
}
void merge(int *arr,int *temp,int start,int end){
if(start>=end)return;
int mid=(start+end)/2;
merge(arr,temp,start,mid);
merge(arr,temp,mid+1,end);
merge_two(arr,temp,start,mid,end);
}
/*
排序算法選擇:1.數據的量n的大小,2.數據的分佈 3. 穩定性(是否改變原相同數值的相當位置)
1. 若n較小,可採用直接插入排序法或選擇排序法
2. 若n較小且數據分佈有序,可以採用直接插入排序法或冒泡排序法
3. 若n大,應採用快排,堆排序,或歸併排序
*/
int main() {
int a[]= {10,4,5,8,3,2,1,7,6,9};
//choice(a,10);
//bubble(a,10);
//direct_insert(a,10);
//shell(a,10,10,2);
//quick(a,0,9);
//heap(a,10);
printf("輸出結果:\n");
int temp[10];
merge(a,temp,0,9);
out(a,10);
return 0;
}
排序算法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.