冒泡排序,插入排序,選擇排序,堆排序代碼

冒泡排序

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
其右孩子的下標是2
i+2
其雙親的下標是(j-1)/2

如某個數組是:56 78 12 23 90 86 45 34
在這裏插入圖片描述
現在需要排序
排序的形式爲key i
key i<=key i2+1;
key i<=key i
2+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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章