1. 程式人生 > 實用技巧 >演算法與資料結構——排序

演算法與資料結構——排序

前提

void X_Sort (ElementType A[], int N)  //預設討論從小到大的整數排序
  • 氣泡排序

void Bubble_Sort(ElementType A[], int N)
{
	for (int P = N - 1; P >= 0; P--)
	{
		int flag = 1;
		for (int i = 0; i < P; i++)
		{
			if (A[i] > A[i + 1])
			{
				Swap(A[i], A[i + 1]); //交換兩數
				flag = 1;
			}
		}
		if (flag == 0) break;//無交換則退出
	}
}
  • 優點:比較穩定,不僅適用於陣列,而且適用於單向連結串列

  • 插入排序

void Insert_Sort(ElementType A[], int N)
{
	int i;
	for (int p = 1; p < N; p++)
	{
		int Tmp = A[p];
		for ( i = p; i > 0 && A[i - 1] > Tmp; i--)
		{
			A[i] = A[i - 1];			
		}
		A[i] = Tmp;
	}
}

優點:穩定


  • 希爾排序

void Sheel_Sort(ElementType A[], int N)
{
	int i;
	for (int D = N / 2; D > 0; D /= 2)	//D為增量序列(此為最原始的希爾排序)
	{
		for (int P = D; P < N; P++)
		{
			int Tmp = A[P];
			for ( i = P; i >= D && A[i - D] > Tmp; i -= D)
			{
				A[i] = A[i - D];
			}
			A[i] = Tmp;
		}
	}
}

增量序列D因情況而異,特殊情況下互質的增量序列是沒有效果的;


  • 選擇排序

void Select_Sort(ElementType A[], int N)
{
	int minid;
	for (int i = 0; i < N; i++)
	{
		minid = i;
		for (int j = i + 1; j < N - 1; j++)
		{
			if (A[j] < A[minid])
			{
				minid = j;
			}
		}
		int tmp = A[i];
		A[i] = A[minid];
		A[minid] = tmp;
	}
}
  • 堆排序


  • 歸併排序

  • 遞迴實現

void merge(ElementType A[], ElementType tempArr[], int left, int mid, int right)
{
	int L_pos = left;
	int R_pos = mid + 1;
	int pos = left;
	while (L_pos <= mid && R_pos <= right)
	{
		if (A[L_pos] < A[R_pos])
		{
			tempArr[pos++] = A[L_pos++];
		}
		else
		{
			tempArr[pos++] = A[R_pos++];
		}
	}
	while (L_pos <= mid)
	{
		tempArr[pos++] = A[L_pos++];
	}
	while (R_pos <= right)
	{
		tempArr[pos++] = A[R_pos++];
	}
	while (left <= right)
	{
		A[left] = tempArr[left];
		left++;
	}
}
void msort(ElementType A[], ElementType tempArr[], int left, int right) 
{
	if (left < right)
	{
		int mid = (left + right) / 2;
		msort(A, tempArr, left, mid);
		msort(A, tempArr, mid + 1, right);
		merge(A, tempArr, left, mid, right);
	}
}
void Merge_sort(ElementType A[], int N)
{
	//分配一個輔助陣列
	int* tempArr = (int*)malloc(N * sizeof(ElementType));
	if (tempArr)
	{
		msort(A, tempArr, 0, N - 1);
                free(tempArr);
	}
	else
	{
		printf("error: failed to allocate memory");
	}
 
}
  • 非遞迴演算法(迴圈實現)
/* L = 左邊起始位置, R = 右邊起始位置, RightEnd = 右邊終點位置*/
void Merge( ElementType A[], ElementType TmpA[], int L, int R, int RightEnd )
{ /* 將有序的A[L]~A[R-1]和A[R]~A[RightEnd]歸併成一個有序序列 */
     int LeftEnd, NumElements, Tmp;
     int i;
      
     LeftEnd = R - 1; /* 左邊終點位置 */
     Tmp = L;         /* 有序序列的起始位置 */
     NumElements = RightEnd - L + 1;
      
     while( L <= LeftEnd && R <= RightEnd ) {
         if ( A[L] <= A[R] )
             TmpA[Tmp++] = A[L++]; /* 將左邊元素複製到TmpA */
         else
             TmpA[Tmp++] = A[R++]; /* 將右邊元素複製到TmpA */
     }
 
     while( L <= LeftEnd )
         TmpA[Tmp++] = A[L++]; /* 直接複製左邊剩下的 */
     while( R <= RightEnd )
         TmpA[Tmp++] = A[R++]; /* 直接複製右邊剩下的 */
    //   該過程可忽略   
   //  for( i = 0; i < NumElements; i++, RightEnd -- )
     //    A[RightEnd] = TmpA[RightEnd]; /* 將有序的TmpA[]複製回A[] */
}
 
void Merge_pass( ElementType A[], ElementType TmpA[], int N, int length )
{ /* 兩兩歸併相鄰有序子列 */
     int i, j;
       
     for ( i=0; i <= N-2*length; i += 2*length )   //只兩兩歸併到倒數第二組,尾巴的情況要單獨考慮
         Merge( A, TmpA, i, i+length, i+2*length-1 );
     if ( i+length < N ) /* 歸併最後2個子列*/
         Merge( A, TmpA, i, i+length, N-1);
     else /* 最後只剩1個子列*/
         for ( j = i; j < N; j++ ) TmpA[j] = A[j];
}
 
void Merge_Sort( ElementType A[], int N )
{ 
     int length; 
     ElementType *TmpA;
      
     length = 1; /* 初始化子序列長度*/
     TmpA = malloc( N * sizeof( ElementType ) );
     if ( TmpA != NULL ) {
          while( length < N ) {
              //迴圈使用A[]和TmpA[],節省了Merge()函式中每次都要將TmpA中有序陣列複製回A的過程
              Merge_pass( A, TmpA, N, length );
              length *= 2;
              Merge_pass( TmpA, A, N, length );
              length *= 2;
          }
          free( TmpA );
     }
     else printf( "空間不足" );
}

未完待續。。。。。