交換排序指當元素位置相反時則把兩個元素交換一下.多次重複這樣的步驟則可排好所有的序.冒泡排序和快速排序都屬於交換排序.
冒泡排序
一講到冒泡兩字你就會想到水裡早泡泡,當然我們要做個假設,就是最輕的泡泡最先泡出來.
方法1:於是根據這樣的思路,從右至左遍曆一下數組,比較相鄰的兩元素,交換位置把小的放前面.這樣一路下來,所有數組中最小的就跑前面去了.接下來把剩下的元素再遍曆兩兩對比並交換,又會得到第二小的.一直這樣重複.
方法2:我們可以把最小的元素冒出來放前面,那麼根據反向思維,先遍曆把最大的找出來放後面也達到同樣的效果.
方法1:先交換出最小的元素
void BubbleSortLittle(int* arr , int len) //arr是指向數組的指標,len是數組長度
{
int tmp;
for(int i = 0; i < len - 1; i++) //從左至右遍曆
{
for(int j = len - 1; j > i; j--) //從右至左遍曆
{
if(arr[j] < arr[j - 1]) //後面的數小於前面的則交換
{
tmp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = tmp;
}
}
}
}
方法2:先交換出最大的元素
void BubbleSortBig(int* arr, int len)
{
int tmp;
for(int i = len - 1; i > 0; i --) //從右至左遍曆
{
for(int j = 0; j < i; j ++) //從左至右遍曆
{
if(arr[j] > arr[j+1]) //前面的數大於後面的則交換
{
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
測試代碼:
int arr[] = { 1,3,2,4,5,7,6,8,9};
int len = sizeof(arr)/sizeof(int);
//BubbleSortLittle(arr , len);
BubbleSortBig(arr, len);
快速排序
我們知道假如一個已排好序的數組,假如是從小到大升序排列,則隨便取其中一個數N,則N左邊所有數都小於或等於N,右邊的都大於或等於N.
那反向思維下,我們先隨便取數組第一個數為基準X,然後將所有小於它的數交換到左邊,大於它的數交換到右邊.最後X可能就被交換到中間某個位置.以X為分界線,數組被分成兩部分.接著再對兩部分重複同樣的操作.這裡用到了遞迴的思想.
快速排序裡面的元素交換又叫填坑,首先取出一個值做標準值basic,則該值所在的位置i變成一個坑,從後面開始遍曆碰到大於X的值(假如下標是j)就把該值交換到位置i,這樣位置j就多出一個坑,從前面遍曆,碰到大於basic的值(假如位置是i)則把該值交換到位置j.這樣i又多出一個坑. 這樣不停的從後到前遍曆,從前到後遍曆,i與j值不斷的變.最後i == j時停止.而此時位置i肯定是空著的,於是把值basic移到這裡來.這樣basic左邊的值都小於它,右邊的都大於它了.
所以整個操作分三步.
1.取一個數作為基準值(可以隨意取一個,不過一般情況取第一個)
2.不停的比較交換資料,使最終基準值左邊的都小於它,右邊的都大於它
3.以步驟2中基準值的位置為中點,把待排序數組分為兩部分,再分別重複步驟2(這裡用了遞迴的思想)
那現在我們不管整個排序過程,先來看下怎麼選一個基準值,然後把交換給左邊的數小於它,右邊的數大於它.
int ChangePos(int* arr, int start , int end) //arr是待排序數組,start是第一個索引,end是最後一個索引
{
int i = start;
int j = end;
int basic = arr[start]; //隨意取一個基準值,這裡就取第一個值.
while( i < j)
{
while( i < j && arr[j] >= basic)
j--;
if( i < j)
{
arr[i] = arr[j];
i++;
}
while(i< j && arr[i] < basic)
i++;
if(i < j)
{
arr[j] = arr[i];
j--;
}
}
arr[i] = basic;
return i; //返回基準值最後所在的位置
}
於是根據這種思路寫排序的演算法應該這樣
void QuickSort(int* arr, int start , int end)
{
if(start < end)
{
int interVal = ChangePos(arr,start,end);
QuickSort(arr,start,interVal - 1);
QuickSort(arr,interVal + 1,end);
}
}
這樣分兩步寫看起來比較清晰易懂點.因為每調用一次ChangePos我們就可以理解為做了一次交換使標準值左邊小於它,右邊大於它了.
不過也可以整合到一個函數裡了.如下
完整的快速排序演算法
void QuickSort(int* arr, int left , int right) //這裡只需要數組第一和最後一個下標.
{
if(left < right)
{
int i = left;
int j = right;
int tmp = arr[left]; //就取左邊第一個數為基準值.
while( i < j) //當i == j時退出迴圈
{
while( i < j && arr[j] >= tmp) //從後向前遍曆,碰到小於tmp的值時停止,該值的索引肯定是j
j--;
if(i < j)
{
arr[i] = arr[j]; //把小於tmp的值arr[j]放到位置i
i++;
}
while(i < j && arr[i] < tmp) //從前向後遍曆,碰到大於tmp的值停止,該值的索引肯定是i
i++;
if(i< j)
{
arr[j] = arr[i]; //把大於tmp的值arr[i]放到位置j
j --;
}
}
arr[i] = tmp; //當i = j時退出迴圈,基準傳值被交換到位置i
QuickSort(arr, left , i - 1); //以基準值tmp為界,用同樣的方式遞迴調用tmp左邊的部分
QuickSort(arr, i + 1, right); //遞迴調用右邊的部分
}
}
測試代碼:
int arr[] = { 1,3,2,4,5,7,6,8,9};
int len = sizeof(arr)/sizeof(int);
QuickSort(arr, 0 , len - 1);