冒泡排序
void bubble_sort(int *ar, int size)
{
assert(ar != NULL);
for (int i = 0; i < size - 1; i++)
{
for (int j = 0; j < size - i - 1; j++)
{
if (ar[j]>ar[j + 1])
{
swap(ar[j], ar[j + 1]);
}
}
}
}
容易出現錯誤的地方是for (int j = i; j < size - i - 1; j++),在這裏看似沒錯,但是如果j是由i賦值的話每次比較大小的開始就不是第一個了,而實跟着i開始比較,這樣就會少比較幾個數
void bubble_sort2(int *ar, int size)
{
assert(ar != NULL);
if (size < 2)
{
return;
}
//int flag1 = 0;
//int flag2 = 0;
for (int i = 0; i < size - 1; i++)
{
bool tag = true;
for (int j = 0; j < size - i - 1; j++)
{
if (ar[j]>ar[j + 1])
{
swap(ar[j], ar[j + 1]);
/* flag2++;*/
tag = false;
}
}
/*if (flag1 != flag2)
{
flag1 = flag2;
}
else break;*/
if (tag)
{
break;
}
}
}
第二個版本的冒泡排序加了一個標識位,如果只需要移動第一位,而其他位不用動,那麼加了標識位後,通過break可以跳出剩餘無用循環
選擇排序
void SelectSort(SeqList &seq) 選擇排序
{
int n = GetSize(seq);
for(int i = 0;i<n-1;++i)
{
int minpos = i;
for(int j = i+1;j<n;++j)
{
if(seq.data[minpos] > seq.data[j])
{
minpos = j;
}
}
if(i != minpos)
{
Swap(seq.data[minpos],seq.data[i]);
}
}
}
插入排序
void InsertSort(SeqList &seq)
{
int n = GetSize(seq);
for(int i = 1;i<n;++i)
{
if(seq.data[i] < seq.data[i-1])
{
ElemType tmp = seq.data[i];
int j = i - 1;
do
{
seq.data[j+1] = seq.data[j];
--j;
}while(j >= 0 && tmp < seq.data[j]);
seq.data[j+1] = tmp;
}
}
}
void FilterDown(SeqList &seq,int start,int end)//建立最小堆,爲優先級隊列和排序做先覺條件
{
int i = start,j = 2*i+1;
ElemType tmp = seq.data[i];//用於最後完成建立後交換原來根節點的值
while(j <= end) //
{
if(j < end && seq.data[j] < seq.data[j+1]) ++j; // Max
if(tmp >= seq.data[j]) break;
seq.data[i] = seq.data[j];
i = j;
j = i*2+1;
}
seq.data[i] = tmp;
}
數據結構的本質是數據之間的關係,如一對一,一對多,多對一,多對多
堆排序
的規律是如某節點的下標是i
則其左孩子的下標是2i+1
其右孩子的下標是2i+2
其雙親的下標是(j-1)/2
如某個數組是:56 78 12 23 90 86 45 34
現在需要排序
排序的形式爲key i
key i<=key i2+1;
key i<=key i2+2;
在建立最小堆時,我們需要從葉節點往根節點構造,因爲如果不降葉節點的最小堆確定,那麼在建立根節點的最小堆時無法確定,原理和關鍵路徑的畫法很相似
所以上面的堆排序的順序是
FilterDown(ar,3,7);
FilterDown(ar,2,7);
FilterDown(ar,1,7);
FilterDown(ar,0,7);
在調用函數是需要確定下標的值,這裏計算的方式是(i-1)/2
在這裏的調用順序是無法改變的,因爲在建立最小堆時,必須先確定其葉節點的最小堆是確定的,否則葉節點以上的節點最小堆也無法確定
如果該數據在末尾增加了一個數
如某個數組是:56 78 12 23 90 86 45 34 5
那麼原來的最小堆就不是最小堆了我們需要重新建立
這時候如果將整個二叉樹進行排序那麼十分浪費時間
我們可以選擇將加入的數和其雙親節點比較,如果其小於雙親節點,則交換和繼續和其雙親節點比較,相當於只對整體的一般的節點進行了排序,這樣的效率較高
void FilterDown(elemtype*ar, int start)//在8下標插入,所以start=8,這時的ar是已近插入了第8個數
{
int i = start;
int j = (i - 1) / 2;
while (i != 0)
{
if (ar[i] < ar[j])
{
swap(ar[i], ar[j]);
i = j;
j = (i - 1) / 2;
}
break;
}
}
堆排序完後取值時,先取根節點(0下標的值),然後把末尾下標的值放在0下標的位置,然後從根節點重新建立最小堆,之後在此取根節點的值,這就是堆排序的核心
下面附上堆排序在優先級隊列中的應用
void FilterDown(ElemType *ar,int start,int end)
{
int i = start,j = 2*i+1; //
ElemType tmp = ar[i];
while(j <= end)
{
if(j < end && ar[j] > ar[j+1]) j+=1;
if(tmp <= ar[j]) break;
ar[i] = ar[j];
i = j;
j = 2*i+1;
}
ar[i] = tmp;
}
void FilterUp(ElemType *ar,int start)
{
int j = start, i = (j-1)/2;
ElemType tmp = ar[j];
while(j > 0)
{
if(ar[i] <= tmp) break;
ar[j] = ar[i];
j = i;
i = (j-1)/2;
}
ar[j] = tmp;
}
下面舉例優先級隊列的輸入和輸出的例子
void FilterDown(ElemType *ar,int start,int end)
{
int i = start,j = 2*i+1; //
ElemType tmp = ar[i];
while(j <= end)
{
if(j < end && ar[j] > ar[j+1]) j+=1;
if(tmp <= ar[j]) break;
ar[i] = ar[j];
i = j;
j = 2*i+1;
}
ar[i] = tmp;
}
void FilterUp(ElemType *ar,int start)
{
int j = start, i = (j-1)/2;
ElemType tmp = ar[j];
while(j > 0)
{
if(ar[i] <= tmp) break;
ar[j] = ar[i];
j = i;
i = (j-1)/2;
}
ar[j] = tmp;
}