1. 09-排序2 Insert or Merge
- 題目
09-排序2 Insert or Merge (25分) 分析
題目輸入原始數組和經過若干步插入排序或者歸併排序的結果,要我們判斷用的是哪個排序,並輸出下一步排序的結果。
插入排序比較簡單,這兒需要注意的是歸併排序最好用非遞歸的歸併排序。
並且在每一步排序之後都要檢查是否和給出的數組相同,如果相同下一次排序之後要輸出。
具體插入排序和歸併排序可以參考我前面的兩篇博客。
http://blog.csdn.net/bobo1356/article/details/71749720
http://blog.csdn.net/bobo1356/article/details/71909977代碼
#include<stdio.h>
#define ElementType int
#define MAXN 101
int arrayEqual(int A[], int B[], int N)
{
int i,ans = 1;
for(i=0; i<N; i++)
{
if(A[i] != B[i])
{
ans = 0;
break;
}
}
return ans;
}
void printArray(int A[], int N)
{
int i;
printf("%d",A[0]);
for(i=1; i<N; i++)
{
printf(" %d",A[i]);
}
printf("\n");
}
void Insert_sort(ElementType A[], ElementType B[], int N){
int i,j;
int equ = 0;
ElementType tmp;
for(i=1; i<N; i++){
tmp = A[i]; //摸下一張牌
for(j=i-1; j>=0 && tmp<A[j]; j--){
A[j+1] = A[j]; //移出空位
}
A[j+1] = tmp; //新牌落位
if(equ == 1)
{
printf("Insertion Sort\n");
printArray(A,N);
break;
}
if(arrayEqual(A,B,N))
{
equ = 1;
}
}
}
void Merge(ElementType A[],ElementType tmpA[], int L, int R, int rightEnd)
{
int tmp = L,leftEnd = R-1,size = rightEnd-L+1;
while(L<=leftEnd && R<=rightEnd)
{
if(A[L] <= A[R]) tmpA[tmp++] = A[L++];
else tmpA[tmp++] = A[R++];
}
while(L<=leftEnd) tmpA[tmp++] = A[L++];
while(R<=rightEnd) tmpA[tmp++] = A[R++];
int i;
for(i=0; i<size; i++) A[rightEnd-i] = tmpA[rightEnd-i];
}
//將A[]中的N個元素歸併到tmpA[]中,其中length表示當前有序子列的長度
void Merge_pass(ElementType A[], ElementType tmpA[], int N, int length)
{
int i;
for(i=0; i<=N-2*length; i+=2*length)
{
Merge(A, tmpA, i, i+length, i+2*length-1);
}
//歸併最後兩個列
if(i+length < N) Merge(A, tmpA, i, i+length, N-1);
else{//如果最後只剩一個子列
for(; i<N; i++) tmpA[i] = A[i];
}
}
void Merge_sort(ElementType A[],ElementType B[], int N)
{
int length = 1, equ = 0;
ElementType *tmpA;
tmpA = malloc(sizeof(ElementType) * N);
if(tmpA != NULL)
{
while(length < N)
{
//將A歸併到tmpA
Merge_pass(A, tmpA, N, length);
length *= 2;
if(equ == 1)
{
printf("Merge Sort\n");
printArray(tmpA, N);
break;
}
if(arrayEqual(tmpA, B, N)) equ = 1;
//將tmpA歸併到A中
Merge_pass(tmpA, A, N,length);
length *= 2;
if(equ == 1)
{
printf("Merge Sort\n");
printArray(A, N);
break;
}
if(arrayEqual(A, B, N)) equ = 1;
}
free(tmpA);
}else
{
printf("空間不足\n");
}
}
int main()
{
int ini[MAXN],res[MAXN];
int tmp[MAXN];
int N,i;
//freopen("insertOrMerge.txt","r",stdin);
scanf("%d",&N);
for(i=0; i<N; i++) scanf("%d",&ini[i]);
for(i=0; i<N; i++) scanf("%d",&res[i]);
for(i=0; i<N; i++) tmp[i] = ini[i];
Insert_sort(tmp,res,N);
for(i=0; i<N; i++) tmp[i] = ini[i];
Merge_sort(tmp,res,N);
return 0;
}
- 小結
這兒有一個優化,可以讓插入排序有一個返回值,如果確實是插入排序,就不再執行歸併排序了。
但我這兒看到N比較小,也就沒有這樣做了。
2. Insertion or Heap Sort
- 題目
09-排序3 Insertion or Heap Sort (25分) - 分析
這道題和上面那一道是同種類型的題目。不過是把判斷歸併排序改成了判斷堆排序。
堆排序要注意的是數組從0還是1的位置開始放入有效元素。如果是從0開始,那麼 leftChild = parent*2;從1開始,那麼 leftChild = parent*2+1。我就是這兒沒注意導致結果一直有問題。
同時我上面說的那個小優化在這次代碼中實現了。 - 我的代碼
#include<stdio.h>
#define ElementType int
#define MAXN 101
int arrayEqual(int A[], int B[], int N)
{
int i,ans = 1;
for(i=0; i<N; i++)
{
if(A[i] != B[i])
{
ans = 0;
break;
}
}
return ans;
}
void printArray(int A[], int N)
{
int i;
printf("%d",A[0]);
for(i=1; i<N; i++)
{
printf(" %d",A[i]);
}
printf("\n");
}
int Insert_sort(ElementType A[], ElementType B[], int N){
int i,j;
int equ = 0, right = 0;
ElementType tmp;
for(i=1; i<N; i++){
tmp = A[i]; //摸下一張牌
for(j=i-1; j>=0 && tmp<A[j]; j--){
A[j+1] = A[j]; //移出空位
}
A[j+1] = tmp; //新牌落位
if(equ == 1)
{
right = 1;
printf("Insertion Sort\n");
printArray(A,N);
break;
}
if(arrayEqual(A,B,N))
{
equ = 1;
}
}
return right;
}
void Filter(ElementType A[], int pos, int N)
{
int child,parent;
ElementType tmp = A[pos];
for(parent=pos; parent*2+1<N; parent=child)
{
child = parent*2+1;
if(child+1<N && A[child]<A[child+1]) child++;
if(A[child] > tmp){
A[parent] = A[child];
}else{
break;
}
}
A[parent] = tmp;
}
void BuildMaxHeap(ElementType A[], int N)
{
int i;
for(i=N/2-1; i>=0; i--) Filter(A, i, N);
}
Swap(ElementType A[], int i, int j)
{
ElementType tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
int Heap_sort(ElementType A[], ElementType B[], int N)
{
int i;
int equ = 0, right = 0;
BuildMaxHeap(A, N);
//printArray(A,N);
for(i=N-1; i>=0; i--)
{
Swap(A, 0, i);
Filter(A, 0, i);
// printArray(A,N);
if(equ == 1)
{
right = 1;
printf("Heap Sort\n");
printArray(A,N);
break;
}
if(arrayEqual(A,B,N))
{
equ = 1;
}
}
return right;
}
int main()
{
int ini[MAXN],res[MAXN];
int tmp[MAXN];
int N,i;
#ifndef ONLINE_JUDGE
freopen("insertOrMerge.txt","r",stdin);
#endif
scanf("%d",&N);
for(i=0; i<N; i++) scanf("%d",&ini[i]);
for(i=0; i<N; i++) scanf("%d",&res[i]);
for(i=0; i<N; i++) tmp[i] = ini[i];
int right = Insert_sort(tmp,res,N);
if(right == 0)
{
for(i=0; i<N; i++) tmp[i] = ini[i];
Heap_sort(tmp,res,N);
}
return 0;
}
- 小結
在這次我學到了一個小技巧:
如果經常在本地代碼進行重定向,從文件輸入,然後提交到OJ上經常忘記註釋的話,可以這樣:
#ifndef ONLINE_JUDGE
freopen("insertOrMerge.txt","r",stdin);
#endif
因爲一般的OJ都會給我們提交的程序加上#define ONLINE_JUDGE
這是一種條件編譯
上述代碼意思就是如果沒有 define ONLINE_JUDGE的話,就會編譯下面的語句;如果已經定義了的話,比如在程序前面加上#define ONLINE_JUDGE
,那麼就不會編譯下面的語句,標準輸入設備還是鍵盤。
還有一種比較常用的條件編譯如下:
#define DEBUG 1
#if DEBUG
printf("%d %d\n",x,y);
#endif
在我們調試程序的時候使 DEBUG 值爲1,就可以輸出一些中間結果,方便程序的調試;當我們調試結束,要提交代碼的時候,可是又不想刪除掉這些輸出語句時(爲了方便以後程序的修改調試),那麼我們只需要修改 DEBUG 的值爲0,編譯器進行預處理的時候就不會編譯下面的這句語句了。
所以條件編譯有時候是很有用的。