1. 程式人生 > >常見排序演算法C++實現(冒泡,直接插入,希爾,堆,歸併,簡單選擇,快排)

常見排序演算法C++實現(冒泡,直接插入,希爾,堆,歸併,簡單選擇,快排)

常見的排序演算法:氣泡排序、直接插入、希爾排序,堆排序,簡單選擇排序,快速排序。這些最基本的演算法都是應該熟練掌握的,下面是C++實現的程式碼,方便大家學習參考:

#include<iostream>
using namespace std;
void swap(int &i,int &j)//實現i,j交換的函式
{
	i=i^j;
	j=i^j;
	i=i^j;
}
void Display(const int *arr,int length)
{
	if(arr==NULL || length<=0)
	{
		return ;
	}
	int i;
	for(i=0;i<length;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl;
}
/*****************直接插入排序***********************/
void InsertSort(int *arr,int length)//直接插入排序
{
	if(arr==NULL || length<=1)//如果大小為1也無需再排序
	{
		return ;
	}
	int i;
	for(i=1;i<length;i++)//從第二個值開始插
	{
		int temp=arr[i];//先儲存待插入的值,因為移動會被覆蓋
		int j;
		for(j=i-1;j>=0 && arr[j]>temp;j--)//一邊比較一邊移動
		{
			arr[j+1]=arr[j];
		}
		if(i!=j+1)//如果前面存在比a[i]小的數
		{
			arr[j+1]=temp;//在當前值的下一個位置插入
		}
	}
}

/*************************氣泡排序**************************/
void BubbleSort(int *arr,int length)//氣泡排序
{
	if(arr==NULL || length<=1)
	{
		return ;
	}
	int i,j;
	bool change=true;//對氣泡排序的優化
	for(i=0;i<length-1 && change;i++)//i表示最多冒泡的次數
	{
		change=false;
		for(j=0;j<length-1-i;j++)
		{
			if(arr[j]>arr[j+1])//通過異或實現高效資料交換
			{
				swap(arr[j],arr[j+1]);
				change=true;
			}
		}
	}
}

/******************簡單選擇排序************************/
void SelectSort(int *arr,int length)//簡單選擇排序
{
	if(arr==NULL || length<=1)
	{
		return ;
	}
	int i,min;
	for(i=0;i<length-1;i++)
	{
		min=i;//每次假設第一個值為最小值
		int j;
		for(j=i+1;j<length;j++)
		{
			if(arr[min]>arr[j])
			{
				min=j;//記下當前最小值的位置
			}
		}
		if(min!=i)
		{
			swap(arr[i],arr[min]);
		}
	}
}
////////////////快速排序////////////////////////////////////
int Partition(int *arr,int left,int right)//將陣列一分為二,並尋找支點的位置
{
	int x=arr[left];//每次將第一個值作為支點的值
	while(left<right)
	{
		while(arr[right]>=x && left<right)//從右向左掃描,注意是小於等於
		{
			right--;
		}
		if(left<right)
		{
			swap(arr[left],arr[right]);
		}

		while(arr[left]<=x && left<right)//從左向右掃描,注意是小於等於
		{
			left++;
		}
		if(left<right)
		{
			swap(arr[left],arr[right]);
		}
	}
	return left;//此時left等於right
}

void QSort(int *arr,int left,int right)//快速排序,left=0,right=length-1
{
	if(left<right)
	{
		int mid=Partition(arr,left,right);
		QSort(arr,left,mid-1);
		QSort(arr,mid+1,right);
	}
}

void QuickSort(int *arr,int length)
{
	if(arr==NULL || length<=1)
	{
		return ;
	}
	QSort(arr,0,length-1);
}

//////////////////////////歸併排序/////////////////////////////////////
void Merge(int *arr,int first,int mid,int last,int *temp)//將arr[first...mid]與arr[mid+1...last]歸併
{
	int i,j;
	int k=0;
	for(i=first,j=mid+1;i<=mid && j<=last;)
	{
		if(arr[i]<=arr[j])//所以是穩定排序
		{
			temp[k++]=arr[i++];
		}
		else
		{
			temp[k++]=arr[j++];
		}
	}
	while(i<=mid)
	{
		temp[k++]=arr[i++];
	}
	while(j<=last)
	{
		temp[k++]=arr[j++];
	}
	for(i=0;i<k;i++)//將合併後的陣列temp[]還原到arr[]
	{
		arr[first+i]=temp[i];//是arr[low+i]不是arr[i]
	}
}
void Msort(int *arr,int first,int last,int *temp)
{
	if(first==last)
	{
		temp[first]=arr[first];
	}
	else if(first<last)
	{
		int mid=(first+last)/2;
		Msort(arr,first,mid,temp);
		Msort(arr,mid+1,last,temp);
		Merge(arr,first,mid,last,temp);
	}
}
void MergeSort(int *arr,int length)//歸併排序
{
	if(arr==NULL || length<=1)
	{
		return ;
	}
	int *temp=new int [length];
	Msort(arr,0,length-1,temp);
	delete []temp;
}

//////////////////希爾排序////////////////////////
void ShellInsert(int *arr,int length,int d)
{
	int i,j;
	for(i=d;i<length;i++)
	{
		int temp=arr[i];
		for(j=i-d;j>=0 && arr[j]>temp;j-=d)
		{
			arr[j+d]=arr[j];
		}
		if(j!=i-d)
		{
			arr[j+d]=temp;
		}
	}
}

void ShellSort(int *arr,int length)//希爾排序
{
	if(arr==NULL || length<=1)
	{
		return ;
	}
	int d=length/2;
	while(d>=1)
	{
		ShellInsert(arr,length,d);
		d/=2;
	}
}

////////////////堆排序(大頂堆)//////////////////////////
///////堆是一個完全二叉樹,若結點索引從0開始,則i結點的左孩子為2*i+1,右為2*i+2
void HeapAdjustDown(int *arr,int length,int i)//對第i個值做向下調整,i=0,...,length-1
{
	if(arr==NULL || length<=0 || i<0)
	{
		return ;
	}
	int temp=arr[i];
	int j;//i相當於前驅,j相當於後繼
	for(j=2*i+1;j<length;)//即j<=length-1
	{
		if(j+1<length && arr[j]<arr[j+1])//如果存在右孩子,且右孩子值待遇
		{
			j++;//與右孩子交換
		}
		if(arr[j]<=temp)//如果左右孩子中的較大值小於該結點值,則說明無需向下調整了
		{
			break;
		}
		else//如果左右孩子中的較大值大於該結點值,則想到直接插入排序
		{
			arr[i]=arr[j];//孩子結點值中較大的上移動
			i=j;//i用於追蹤待插入點的位置
			j=2*i+1;
		}
	}
	if(arr[i]!=temp)//如果i的值發生了移動
	{
		arr[i]=temp;//將最初第i個節點值放入合適的位置
	}

}
void CreateHeap(int *arr,int length)//建立一個堆
{
	if(arr==NULL || length<=0)
	{
		return ;
	}
	int i;
	for(i=(length-2)/2;i>=0;i--)//最後一個元素的序號為length-1,故該結點的父結點為(length-2)/2
	{
		HeapAdjustDown(arr,length,i);//從倒數第二行開始倒著向下調整
	}
}
void HeapDelete(int *arr,int len)//刪堆頂元素,len表示當前表的長度
{
	if(arr==NULL || len<=0 || len==1)//len=1,表示當堆中只有一個元素時,無需排序
	{
		return ;
	}
	else
	{
		swap(arr[0],arr[len-1]);
		HeapAdjustDown(arr,len-1,0);//刪除後,陣列長度減1了
	}
}

void HeapSort(int *arr,int length)//堆排序
{
	if(arr==NULL || length<=1)
	{
		return ;
	}
	CreateHeap(arr,length);//先建立一個堆0
	int i;
	for(i=0;i<=length-1;i++)//刪除length-1次即可,因為最後一個元素就剩自己了
	{
		HeapDelete(arr,length-i);
	}
}
int main()
{
	int a[]={12,3,5,1,4,5,4,21,1,3};
	Display(a,sizeof(a)/sizeof(int));//顯示排序前的元素
	//void (*pSort)(int*,int)=NULL;//定義一個函式指標,方法一
	typedef void (*Fun)(int *,int);//Fun為函式指標類
	Fun pFunc=NULL;//定義函式指標,方法二,與上面等價
	pFunc=InsertSort;
//	pFunc=BubbleSort;
//	pFunc=SelectSort;
//	<span style="font-family: Arial, Helvetica, sans-serif;">pFunc</span><span style="font-family: Arial, Helvetica, sans-serif;">=QuickSort;</span>
//	<span style="font-family: Arial, Helvetica, sans-serif;">pFunc</span><span style="font-family: Arial, Helvetica, sans-serif;">=ShellSort;</span>
//	pFunc=HeapSort;
	if(pSort)
	{
		pSort(a,sizeof(a)/sizeof(int));//顯示排序後的元素
	}
	Display(a,sizeof(a)/sizeof(int));
	system("pause");
	return 0;
}