[置頂] 各類排序算法的講解與實現

排序的分類:

1 內部排序

 內部排序:在整個排序過程當中不需不訪問外存便能完成,稱這樣的排序問題爲內部排序;html

1.1 插入排序

      插入排序: 將無序序列中的一個或幾個記錄「插入」到有序的序列中,從而增長記錄的有序序列的長度。ios

     主要思想是將第一個元素看作是有序的,從第二個元素起將待排序的元素插入到有序序列中,使序列逐漸擴大,直到全部的元素都插入到有序序類中。算法

直接插入排序

    基本思想是將記錄R[i]插入到有序序列R[1..i-1],使記錄的有序序列從R[1..i-1]變爲R[1..i]。sql

    直接插入排序算法最好狀況下的時間複雜度爲O(n),最壞狀況的時間複雜度和平均時間複雜度爲O(n^2)。shell

#include "stdafx.h"
#include "stdafx.h"
#include <iostream>
using namespace std;

void StrInsSort (int number  ,int r[])
{
	int temp;
	for(int i=1;i<=number;i++)
	{
		temp=r[i];int j=i-1;
		while(temp<r[j])
		{
			r[j+1]=r[j];
			j--;
		}
		r[j+1]=temp;
	}
}

int _tmain(int argc, int argv[])
{
	std::cout<<"輸入數組大小"<<endl;
	std::cin>> argc;
	std::cout<<"輸入數組內數據"<<endl;
	for(int j=0;j<argc;j++)
	{  
		std::cin>>argv[j];
	}
	StrInsSort (argc ,argv);
	for(int j=0;j<argc;j++)
	{  
		std::cout << argv[j] << std::endl; 
	}
	system("pause");
	return 0;
}

次待排序數組是從0開始的,先假定第0個元素是有序的,從第一個元素起與前邊的有序序列進行比較,T先和下標爲i-1的數組比較,(生成的整個序列是從小到達排列的)若是數組

r[i]>r[i-1],則直接放在r[i]的位置,不然若是T<r[i-1],則將將i--,直到找到一個比T小的,把T放在該數的後邊;數據結構

 

折半插入排序

    折半插入與直接插入比較,當第i 個記錄要插入到前i-1個記錄序列時,能夠利用折半查找方式肯定插入位置,以減小比較次數。函數

    折半查找明顯減小了關鍵字的「比較」次數,單記錄的移動次數不變,故時間複雜度仍爲O(n^2)。測試

 

void BinSort (int count, int R[])
{
	for (int i=1;i<=count;i++)
	{
		int left=0;
		int right=i-1;
		int temp;
		while (right>=left)
		{
			temp=R[i] ;
			int mid =(left+right)/2;
			if (temp>R[mid])
			{
				left=mid+1;
			} 
			else
			{
				right=mid-1;
			}
		}
		for (int j=i-1;j>=right+1;j--)
		{
			R[j+1]=R[j];
		}
		R[right+1]=temp;
	}
};


函數寫過程當中,首先肯定有多少個元素要參加排序,因爲次數組是從下表0開始的,因此和直接插入排序同樣,先假設第0個元素是有序的,則從下標爲1的元素開始執行循環,即從1到count個元素都要執行對比循環過程;其循環內部基本思路是,把取到的第i個元素插入到前0到i-1個元素中,由於前i個元素是有序的,因此二分查找是拿第i元素和和前面有序數列中的第mid =(left+right)/2個元素比較,即有序數列中中間的那個元素,由於排序後要生成一個從小到大排序的數列,即升序數列,因此若是temp>R[mid]以下圖所示,ui

0 2 4 6 7 9 11

 則要是插入 temp後整個數列依然有序,則temp必須在6的後面,因此要最左側的數爲left=mid+1;才能保證在後半部分尋找數據;

而後就要判斷循環何時終止,由於在整個循環過程當中不斷縮小循環的範圍,即left和right的距離愈來愈近,當left==right時,這時mid==left==righ, 這時,

若是      

  if (temp>R[mid])
   {
    left=mid+1;
   }     

如上圖所示,mid在6的位置,此時的temp是>6而<7 的,應該把>=left的或>=mid+1的或>=right+1的元素向後移一位;

而若是   

else
   {
    right=mid-1;
   }

如上圖所示,mid應該<6且>4,即放在4和6之間,這樣更應該把>=left的後>=mid的或>=right+1的元素向後移一位;

  for (int j=i-1;j>=right+1;j--)
  {
   R[j+1]=R[j];
  }           即對應這段程序;

 通過上邊分析,一樣也能夠寫成下面程序,即把>=right+1,改爲>=left;

 for (int j=i-1;j>=left;j--)
  {
   R[j+1]=R[j];
  }
  R[left]=temp;

 

二路插入排序

    基本思想是另設一數組d,將R[1]複製給d[1],並將d[1]看作排好序的「中間」記錄,從第二個起依次將關鍵字小於d[1]的記錄插入到d[1]以前的有序序列中,將關鍵字大於d[1]的記錄插入到d[1]以後的有序序列中。這裏藉助兩個變量first和final來指示排序過程當中有序序列第一個記錄和最後一個記錄在d中的位置。

       

int BiInsertSort()
{
	//二路插入排序算法
	int iRawBuff[6] ={0,9,6,7,3,2};
	int final = 0;
	int first = 0;
	const int iLenght = 5;

	int iTempBuff[iLenght] = {0};

	iTempBuff[0] = iRawBuff[0];
	for (int i = 1; i <= iLenght;i++)
	{
		if(iRawBuff[i] > iTempBuff[final])
		{
			//大於當前最大值,後插
			final++;
			iTempBuff[final] = iRawBuff[i];

		}
		if(iRawBuff[i]< iTempBuff[first])
		{
			//小於當前最小值,前插
			first = (first-1+iLenght)%iLenght;
			iTempBuff[first] = iRawBuff[i];

		}
		if(iRawBuff[i] < iTempBuff[final]&&iRawBuff[i] > iTempBuff[first])
		{
			//大於當前最小值,小於當前最大值,中間插
			int j = final++;
			while (iRawBuff[i] < iTempBuff[j])
			{
				iTempBuff[(j+1)%iLenght] = iTempBuff[j];
				j = (j-1+iLenght)%iLenght;
			}
			iTempBuff[j+1] = iRawBuff[i];

		}
		printf("第%d趟:\n",i-1);
		for(int k = 0; k < iLenght; k++)
		{
			std::cout<<iTempBuff[k]<<"\t";
		}
		std::cout<<std::endl;
	}
	//導入輸入到原始數組中
	for (int k = 0; k < iLenght; k++)
	{
		iRawBuff[k+1] = iTempBuff[(first++)%iLenght];
	}
	return 0;
}


    運行結果:

           

 

 因爲first在增長增長的過程當中,沒有最大值的限制,爲了防止生成的數組發生越界,因此對這些數取iLenght的餘數,即用%iLenght。

 

表插入排序

    爲了減小在排序過程當中「移動」記錄的操做,必須改變排序過程當中採用的存儲結構。利用靜態鏈表進行排序,並在排序以後,一次性地調整各個記錄之間的位置,即將每一個記錄都調整到他們應該在的位置上,這樣的排序方法稱爲表插入排序。

基本思想:

使頭結點的next域始終指示最小的那個元素,而後依次向下:每個元素的next域都指示比它稍大的那個元素。最大的元素的next域指示頭結點。

下面分三步給出具體的代碼:

一、用數組初始化表結構。

二、修改next域造成有序的循環鏈表。

三、根據next域信息調整表結構中的數組,是數據從小到大排列。

 

#include "stdafx.h"
#define INT_MAX 100
#define number 100
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<iomanip>
#include<math.h>

//排序後按從小到大輸出

using namespace std;
typedef struct  
{
	int key;
	int other;  //記錄其餘數據域
	int next;
}STListType;

STListType SL[number+1];


void ListInsSort(STListType SL[],int n)
{
	//對記錄序列SL[1..n]進行表插入排序
	SL[0].key = 10000;
	SL[0].next=1;
	SL[1].next=0;               //初始化,假定第一個記錄有序
	int k;
	for (int i=2; i<n ; i++)    //查找插入位置
	{
		int j=0;
		for (k=SL[0].next;SL[k].key<SL[i].key;)  //保證[k].key>=[i].key
		{
			j=k, k=SL[k].next;                   //保證是SL[k]裏的老是最大的               
		}
		SL[j].next=i;     //結點i插入在結點j和結點k之間  SL[j]<=SL[i]<=SL[k] 
		SL[i].next =k; 

		cout<<"ListInsSort-key:\n";
		for(int count=0;count<n;count++)
			cout<<setw(4)<<SL[count].key;
		cout<<endl;
		cout<<"ListInsSort-next:\n";
		for(int count=0;count<n;count++)
			cout<<setw(4)<<SL[count].next;
		cout<<endl;
	}
}

void Arrange(STListType SL[],int n)
{
	//根據靜態表SL中各節點的指針值調整記錄位置,使得SL中的記錄關鍵字非遞減有序順序排列
	//p指示第i個記錄的當前位置;i指示第i個記錄應在的位置;q指示第i+1個記錄的當前位置;
	int p=SL[0].next;                                  //p指示第一個記錄的當前位置
	int q;
	for (int i=1;i<n;i++)
	{
		//SL[1..i-1]中的記錄關鍵字有序排列,第i個記錄在SL中的當前位置應不小於i
		//爲了保證<i 的元素都是有序的
		while(p<i)                         //找到第i個記錄,並用p指示其在SL中的當前位置
			p=SL[p].next;
		q=SL[p].next;                      //q指示還沒有調整的表尾
		if (p!=i)
		{
			STListType temp;
			temp = SL[p];
			SL[p] = SL[i];
			SL[i] = temp;                    //交換記錄,使第i個記錄到位 
			SL[i].next=p;                       //指向被移走的記錄,使得之後能夠由while循環找到                          
		}
		p=q;                                    //p指示還沒有調整的表尾,爲找第i+1個記錄做準比

		cout<<"Arrange-key:\n";
		for(int count=0;count<n;count++)
			cout<<setw(4)<<SL[count].key;
		cout<<endl;
		cout<<"Arrange-next:\n";
		for(int count=0;count<n;count++)
			cout<<setw(4)<<SL[count].next;
		cout<<endl;
	}	
}

int _tmain()
{
	STListType SL[100];
	int n;
	cout<<"ListInsSort.cpp運行結果:\n";
	int b[100],i;
	srand(time(0));
	cout<<"輸入待排序元素個數n:";cin>>n;
	for(i=1;i<n;i++)
	{
		b[i]=rand()%100;
		SL[i].key=b[i];
	}
	cout<<"排序前數組:\n";
	for(i=1;i<n;i++)
		cout<<setw(4)<<b[i];
	cout<<endl;
	ListInsSort(SL,n);
	Arrange(SL,n);
	cout<<"排序後數組:\n";
	for(i=1;i<n;i++)
		cout<<setw(4)<<SL[i].key;
	cout<<endl;
	system("pause");   
}

 

希爾插入排序

    希爾排序又稱縮小增量排序,(適用於待排序數列很無序的狀況下);基本思想是將待排序的記錄劃分紅幾組,從而減小參與直接插入排序的數據量,通過幾回分組排序後,記錄的排序已經基本有序,在對全部的記錄實施最後的直接插入排序。

     對於希爾排序,具體步驟能夠描述以下:假設待排序的記錄爲n個,先取整數d<n,例如d=n/2,將全部距離爲d的記錄構成一組,從而將整個待排序記錄分割成爲d個子序列(d組),對每一個分組進行直接插入排序,而後再縮小間隔d,例如,取d=d/2,重複上述分組,再對每一個分組分別進行直接插入排序,直到最後取d=1,即將全部的記錄放在一組進行一次直接插入排序,最終將全部記錄從新排列成按關鍵字有序的序列。

Shell提出的選法:d1=n/2 , di+1=di/2

#include<iostream>
#include<iomanip>
#include<stdlib.h>
#include<time.h>
using namespace std;

#define MAXI 11
typedef int KeyType;
typedef int ElemType;
struct rec 
{
	KeyType key;
	ElemType data;
};
typedef rec sqlist[MAXI];

void shellsort(sqlist b,int n)
{
	int i,j,gap,k;
	rec x;
	gap=n/2;
	while(gap>0)
	{
		for(i=gap+1;i<n;i++)
		{
			j=i-gap;
			while(j>0)
			if(b[j].key>b[j+gap].key)
			{
				x=b[j];
				b[j]=b[j+gap];
				b[j+gap]=x;
				j=j-gap;
			}
			else j=0;
			for(k=1;k<n;k++)
				cout<<setw(4)<<b[k].key;
			cout<<endl;
		}
		gap=gap/2;
	}
}

void main()
{cout<<"運行結果:\n";
sqlist a;int i,n=MAXI;
srand(time(0));
for(i=1;i<n;i++)
{a[i].key=rand()%80;
a[i].data=rand()%100;}
cout<<"排序前數組:\n";
for(i=1;i<n;i++)
	cout<<setw(4)<<a[i].key;
cout<<endl;
cout<<"數組排序過程演示:\n";
shellsort(a,n);
cout<<"排序後數組:\n";
for(i=1;i<n;i++)
	cout<<setw(4)<<a[i].key;
cout<<endl;cin.get();}

1.2 交換排序

      交換排序:經過「交換」無序序列中的相鄰記錄從而獲得其中關鍵字最小或最大的記錄,並將他們加入到有序序列中,以增長記錄的有序序列長度。

      主要思想是在排序過程當中,經過比較待排序記錄序列中元素的關鍵字,若是發現次序相反,則將存儲位置交換來達到排序目的。

起泡排序

     它的基本思想是對全部相鄰記錄的關鍵字值進行比較,若是是逆序(a[j]>a[j+1]),則將其交換,最終達到有序。

  

#include "stdafx.h"
#include "stdafx.h"
#include <iostream>
using namespace std;

int bubbleSort (int number  ,int r[])
{
	int  temp;
	for (int i =0;i<=number-1;i++)
	{
		for (int j=0;j<=number-i-1;j++)
		{
			if (r[j]>r[j+1])
    			{
				temp=r[j];
				r[j]=r[j+1];
				r[j+1]=temp;
			}
		}
	}

	return 1;
}

int _tmain(int argc, int argv[])
{
	std::cout<<"輸入數組大小"<<endl;
	std::cin>> argc;
	std::cout<<"輸入數組內數據"<<endl;
	for(int j=0;j<argc;j++)
	{  
		std::cin>>argv[j];
	}
	bubbleSort (argc ,argv);
	for(int j=0;j<argc;j++)
	{  
		std::cout << argv[j] << std::endl; 
	}
	system("pause");
	return 0;
}

在排序過程當中,比較相鄰的元素,若是第前個比後一個大,就交換他們兩個。對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。針對全部的元素重複以上的步驟,除了最後一個。

for (int i =0;i<=number-1;i++)循環是指(一個元素向上冒泡,直到它找到合適的位置)這個過程的次數,即有多少個元素要進行冒泡操做;冒到上邊的是最大的;

for (int j=0;j<=number-i-1;j++)循環是指進行冒泡操做的每個元素,要通過作少次對比,才能找到合適的位置;

 快速排序

     快速排序的基本思想:首先將待排序記錄序列中的全部記錄做爲當前待排序區域,從中任選一個記錄(一般可選取第一個記錄),以它的關鍵字做爲樞紐,凡其關鍵字小於樞紐的記錄均移到該記錄以前,反之,凡關鍵字大於樞紐的記錄均移至該紀錄以後,這樣一趟排序以後,記錄的無序序列R[s..t]將分割成兩部分:R[s..i-1]和R[i+1..t],且R[j].key<=R[i].key<=R[k].key

 

#include "stdafx.h"
#include "stdafx.h"
#define number 100
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<iomanip>
#include<math.h>

//排序後按從小到大輸出

using namespace std;
typedef struct  
{
	int key;
	int other;  //記錄其餘數據域
	int next;
}RecType;

RecType S[number+1];

int Partirion(RecType R[],int l,int h)
{
	//交換記錄子序列R[1..h]中的記錄,使樞紐記錄交換到正確的位置,並返回其所在的位置
	int i=l;
	int j=h;              //用變量i,j記錄待排序記錄的首尾位置
	R[0]=R[i];            //以子表的第一個記錄做爲樞軸,將其暫存到記錄R[0]中
	int x=R[i].key;       //用變量x存放樞紐記錄的關鍵字
	while (i<j)
	{
		//從表的兩端交替地向中間掃描
		while (i<j&&R[j].key>=x)
		{
			j--;
		}
		R[i]=R[j];          //將比樞紐小的記錄移到低端
		while (i<j&&R[i].key<=x)
		{
			i++;
		}
		R[j]=R[i];          //將比樞紐大的記錄移到高端
	}
	R[i]=R[0];              //樞紐記錄到位
	return i;               //返回樞紐位置
}


void QuickSort(RecType R[],int s,int t)
{
	//對記錄序列R[s..t]進行快速排序
	if (s<t)
	{
		int k,i;
		k=Partirion(R,s,t);
		QuickSort(R,s,k-1);
		QuickSort(R,k+1,t);
		cout<<"QuickSort:\n";
		for(i=2;i<=t;i++)
			cout<<setw(4)<<R[i].key;
		cout<<endl;
	}
}

int _tmain()
{
	RecType SL[100];
	int n;
	cout<<"QuickSort.cpp運行結果:\n";
	int b[100],i;
	srand(time(0));
	cout<<"輸入待排序元素個數n:";cin>>n;
	for(i=1;i<n;i++)
	{
		b[i]=rand()%100;
		SL[i].key=b[i];
	}
	cout<<"排序前數組:\n";
	for(i=1;i<n;i++)
		cout<<setw(4)<<b[i];
	cout<<endl;
	QuickSort(SL,1,n);
	cout<<"排序後數組:\n";
	for(i=2;i<=n;i++)
		cout<<setw(4)<<SL[i].key;
	cout<<endl;
	system("pause");   
}

運行結果:

 

 

1.3 選擇排序

      選擇排序:從記錄的無序序列中「選擇」關鍵字最小或最大的記錄,並將他加入到有序子序列中,以增長記錄的有序序列的長度。

      基本思想是依次從待排序記錄中選擇出關鍵字值最小(或最大)的記錄、關鍵字值次之的記錄、...並分別將它們定位到序列左側(或右側)的第1位置、第2位置、...,從而使待排序的記錄序列成爲按關鍵字值由小到大(或有大到小)排列的有序序列。

直接選擇排序

     有序序列中全部記錄的關鍵字均小於無序序列中記錄的關鍵字,則第i趟直接選擇排序是從無序序列R[i..n]的n-i+1個記錄中選擇關鍵字最小的記錄加入有序序列的末尾。

     

#include "stdafx.h"
#define number 100
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<iomanip>
#include<math.h>
//排序後按從小到大輸出
using namespace std;
typedef struct 
{
	int key;
	int other; //記錄其餘數據域
	int next;
}RecType;
RecType S[number+1];
void SelectSort(RecType R[],int n)
{
	//對記錄序列R[1..n]進行直接選擇排序
	for (int i=1;i<n;i++)
	{
		int k=i;
		for (int j=i+1;j<=n;j++)
		{
			if (R[k].key>R[j].key)
			{k=j;}
		}
	if (i!=k)
	{
		RecType temp;
		temp=R[i];
		R[i]=R[k];
		R[k]=temp;
	}
	}
}
int _tmain()
{
	RecType SL[100];
	int n;
	cout<<"SelectSort.cpp運行結果:\n";
	int b[100],i;
	srand(time(0));
	cout<<"輸入待排序元素個數n:";
	cin>>n;
	for(i=1;i<n;i++)
	{
		b[i]=rand()%100;
		SL[i].key=b[i];
	}
	cout<<"排序前數組:\n";
	for(i=1;i<n;i++)cout<<setw(4)<<b[i];
	cout<<endl;SelectSort(SL,n);
	cout<<"排序後數組:\n";
	for(i=2;i<=n;i++)
		cout<<setw(4)<<SL[i].key;
	cout<<endl;
	system("pause"); 
}


 

     

樹形選擇排序

     基本思想:首先是對n個待排序記錄的關鍵字進行兩兩比較,從中選出[n/2]個較小者再兩兩比較,直到選出關鍵字最小的記錄爲止,此爲一趟排序。

#include "stdafx.h"

//錦標賽排序法
#include<iostream>
#include<iomanip>
#include<math.h>
#include<stdlib.h>
#include<time.h>

using namespace std;
class DataNode //勝者樹結點的類定義
{public:
int data;//數據值
int index;//樹中的結點號
int active;//參選標誌
};
//錦標賽排序中的調整算法;i是表中當前
//最小元素的下標,即勝者.從它開始向上調整
void UpdataTree(DataNode *tree,int i)
{int j;
if(i%2==0) //i爲偶數,對手爲左結點
	tree[(i-1)/2]=tree[i-1];//i爲奇數,對手爲右結點
else
	tree[(i-1)/2]=tree[i+1];
i=(i-1)/2; //i上升到雙親結點位置
while(i)
{if(i%2==0) j=i-1;//肯定i的對手爲左結點仍是右結點
else j=i+1;
if(!tree[i].active||!tree[j].active)//比賽對手中間有一個空
	if(tree[i].active) tree[(i-1)/2]=tree[i];
	else tree[(i-1)/2]=tree[j]; //非空者上升到雙親結點
else                         //比賽對手都不爲空
	if(tree[i].data<tree[j].data) tree[(i-1)/2]=tree[i];
	else tree[(i-1)/2]=tree[j];//勝者上升到雙親結點
	i=(i-1)/2; //i上升到雙親結點
}}
//創建樹的順序存儲數組tree,將數組a[]中的元素複製到勝者樹中,
//對它們進行排序,並把結果返回數組中,n是待排序元素個數
void TournmentSort(int a[],int n)
{DataNode *tree; //勝者樹結點數組
DataNode item;
int m,i,j=0;
for(int k=0;k<n;k++)//計算知足>=n的2的最小次冪的數
{
	m=(int)pow((double) 2,(double)k);
	if(m>=n)
		break;
}
int bottomRowSize=m;
int TreeSize=2*bottomRowSize-1;//計算勝者樹的大小:內結點+外結點數
int loadindex=bottomRowSize-1;//外結點開始位置
tree=new DataNode[TreeSize];  //動態分配勝者樹結點數組空間
for(i=loadindex;i<TreeSize;i++)//複製數組數據到樹的外結點中
{tree[i].index=i;//下標
if(j<n) {tree[i].active=1;tree[i].data=a[j++];}//複製數據
else tree[i].active=0; //後面的結點爲空的外結點
}
i=loadindex;           //進行初始比較尋找最小的項
while(i)
{j=i;
while(j<2*i)          //處理各對比賽者
{if(!tree[j+1].active||tree[j].data<tree[j+1].data)
tree[(j-1)/2]=tree[j];
else tree[(j-1)/2]=tree[j+1];//勝者送入雙親
j+=2; //下一對參加比較的項
}
i=(i-1)/2;//i退到雙親,直到i=0爲止
}
for(i=0;i<n-1;i++)//處理其餘n-1個元素
{a[i]=tree[0].data;//當前最小元素送數組a
tree[tree[0].index].active=0;//該元素相應外結點再也不比賽
UpdataTree(tree,tree[0].index);//從該處向上修改
}
a[n-1]=tree[0].data;
}
//錦標賽排序法的測試
void main()
{cout<<"JinBiaoSai.cpp運行結果:\n";
int n,b[100],i;
srand(time(0));
cout<<"輸入待排序元素個數n:";cin>>n;
for(i=0;i<n;i++) b[i]=rand()%100;
cout<<"排序前數組:\n";
for(i=0;i<n;i++)
	cout<<setw(4)<<b[i];
cout<<endl;
TournmentSort(b,n);
cout<<"排序後數組:\n";
for(i=0;i<n;i++)
	cout<<setw(4)<<b[i];
cout<<endl;
cin.get();cin.get();
}


 

 

 

樹形選擇排序:

#include "stdafx.h"
#include<iostream> 
#include<string.h> 
#include<ctype.h> 
#include<malloc.h> 
#include<limits.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<io.h> 
#include<math.h>

using namespace std;

#define MAX_SIZE 20 
typedef int KeyType;
typedef int InfoType; //定義其餘數據類型 
struct RedType{ KeyType key; InfoType otherinfo; };  
struct SqList
{ 
	RedType r[MAX_SIZE];    
    int length; 
};
void print(SqList L)
{ 
	int i; 
	for(i=1;i<=L.length;i++) 
		cout<<"("<<L.r[i].key<<","<<L.r[i].otherinfo<<")"; 
	cout<<endl; 
}

void TreeSort(SqList &L)
{ 
	int i,j,j1,k,k1,l;
	float n=L.length; 
	RedType *t; 
	l=(int)ceil(log(n)/log(2.0))+1; //徹底二叉樹的層數;ceil取上整,返回比x大的最小整數
	k=(int)pow(2.0,l)-1; //k爲l層徹底二叉樹的結點總數 
	k1=(int)pow(2.0,l-1)-1; //k1爲l-1層二叉徹底二叉樹的結點總數 
	t=(RedType*)malloc(k*sizeof(RedType)); //二叉樹採用順序存儲 
	for(i=1;i<=n;i++) //將L.r賦值給葉子結點 
		t[k1+i-1]=L.r[i]; 
	for(i=k1+n;i<k;i++) //給多餘的葉子結點的關鍵字賦無窮大值 
		t[i].key=INT_MAX; 
	j1=k1; 
	j=k; 
	while(j1)
	{ 
		//給非葉子結點賦值 
		for(i=j1;i<j;i+=2)
		{
			t[i].key<t[i+1].key?(t[(i+1)/2-1]=t[i]):(t[(i+1)/2-1]=t[i+1]); 
		}		
		j=j1; j1=(j1-1)/2; 
		cout<<"給非葉子結點賦值:"<<endl;     //循環一次,找到最小的
		print(L); 
	} 
	for(i=0;i<n;i++)
	{ 
		L.r[i+1]=t[0]; //鍵當前最小值賦給L.r[i] 
		j1=0; 
		for(j=1;j<l;j++) //沿樹根找到結點t[0]在葉子結中的序號j1 
			t[2*j1+1].key==t[j1].key?(j1=2*j1+1):(j1=2*j1+2); 
		t[j1].key=INT_MAX; 
		while(j1)
		{ 
			j1=(j1+1)/2-1; //序號爲j1的節點的雙親節點序號 
			t[2*j1+1].key<=t[2*j1+2].key?(t[j1]=t[2*j1+1]):(t[j1]=t[2*j1+2]); 
		} 
		cout<<"循環排序:"<<endl; 
		print(L); 
	} 
	free(t); 
}
#define N 8
void main()
{ 
	RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}}; 
	SqList l; 
	int i; 
	for(i=0;i<N;i++) 
		l.r[i+1]=d[i]; 
	l.length=N; 
	cout<<"排序前:"<<endl; 
	print(l); 
	TreeSort(l); 
	cout<<"排序後:"<<endl; 
	print(l); 
	system("pause"); 
}

 

排序過程當中t[k1+i-1]=L.r[i];把L裏的數據存儲t[k1+i-1]中,爲排序須要

k=(int)pow(2.0,l)-1; //k爲l層徹底二叉樹的結點總數

t=(RedType*)malloc(k*sizeof(RedType)); //二叉樹採用順序存儲

的存儲空間;

運行結果:

 

堆排序

     其左右子樹分別是堆,任何一個結點的值不大(或不小於)左右孩子節點,則最頂端元素必是序列中的最大值或最小值,分別稱爲小頂堆或大頂堆(小堆或大堆)。堆排序是利用堆的特性對記錄序列進行排序的一種排序算法。其基本思想是:先建一個堆,即先選一個關鍵字最大或最小的記錄,而後與序列中的最後一個記錄交換,以後將序列中前n-1個記錄從新調整爲一個堆(調堆的過程稱爲「篩選」),再將堆頂記錄和第n-1個記錄交換,如此反覆至排序結束。注意:第i 次篩選的前提是從2到n-i 是一個堆,即篩選是對一棵左/右子樹均爲堆的徹底二叉樹「調整」根節點使整棵二叉樹爲堆的過程。

#include "stdafx.h"
#include <iostream>
using namespace std;

void sift(int R[],int i,int m) //R[]要排序的數組;i是指是從堆的第幾行的首元素 即i=1 2 4 8 16...;m是指數組中一共多少個元素
{
	//設R[i+1..m]中各元素知足堆的定義,本算法調整R[i]使序列R[i..m]中的元素知足堆的性質
	int temp = R [i];
	for (int j=2*i;j<=m;j*=2)
	{
		 //在堆的同一層進行比較,若是右邊的大於左邊的,則繼續向右查找 ,爲了保證下面和temp比較的R[j],是這一層上最大的一個
		if ((j<m)&&(R[j]<R[j+1])) 
		{
			j++;
		}
		if (temp<R[j]) //temp和每一層最大的數比較,若是小於最大的,則把最大的的值賦給R[i]
		{
			R[i]=R[j];
			i=j;         //修改i的值,此時R[i]=R[j]的值相同       
		} 
		else
		{
			break;
		}
	}
	R[i]=temp;         //最初要調整的節點放在正確的位置
}

void  HeapSort( int R[],int n)
{
	int i ;
	int nCreateTime=1;
	for (i=n/2;i>0;i--)
	{
		sift(R,i,n);    //建堆時i從n/2起遞減,是指i從從最底層起依次循環向頂層排序 
		std::cout<<"建堆"<<nCreateTime<<endl;
		for(int j=1;j<9;j++)  
		{ 
			std::cout << R[j];   
		}
		nCreateTime++;
		std::cout<<endl;
	}
	int nAdjustTime=1;
	for (i=n;i>1;i--)
	{
		int temp ;
		temp=R[i];
		R[i]=R[1];
		R[1]=temp;
		sift(R,1,i-1);
		std::cout<<"從新調整"<<nAdjustTime<<endl;
		for(int j=1;j<9;j++)  
		{ 
			std::cout << R[j];   
		}
		nAdjustTime++;
		std::cout<<endl;
	}

}

int _tmain(int argc, _TCHAR* argv[])
{
	int data[9]={0,6,9,3,1,5,8,9};
	std::cout<<"初始序列"<<endl;
	for(int j=1;j<9;j++)  
	{    
		std::cout << data[j];   
	}
	std::cout<<endl;
	HeapSort( data,8);
	std::cout<<"生成的有序序列"<<endl;
	for(int j=1;j<9;j++)  
	{    
		std::cout << data[j];   
	}
	std::cout<<endl;
	system("pause");  
	return 0;
}

運行結果:


 

1.4 歸併排序

      歸併排序:經過「歸併」兩個或兩個以上的有序序類,逐步增長有序序列的長度。

歸併排序 2-路歸併排序

     其基本思想是:將一個具備n個待排序記錄的序列當作是n個長度爲1的有序序列,而後進行兩兩歸併,獲得n/2個長度爲2的有序序列,在進行兩兩歸併,獲得n/4個長度爲4的有序序列,如此重複,直至獲得一個長度爲n的有序序列爲止。

 

#include "stdafx.h"
#define number 100
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<iomanip>
#include<math.h>

//排序後按從小到大輸出

using namespace std;
typedef struct  
{
	int key;
	int other;  //記錄其餘數據域
	int next;
}RecType;

RecType S[number+1];

void Merge(RecType R[],RecType R1[],int i,int l,int h)
{
	//將有序的R[i..l]和R[l+1..h]歸併爲有序的R1[i..h]
	int j;
	int k;
	for (j=l+1,k=i;i<=l && j<=h;k++)
	{
		//將R[]中記錄由小到大地併入R1
		if (R[i].key<=R[j].key)
		{
			R1[k]=R[i++];
		} 
		else
		{
			R1[k]=R[j++];
		}
	} //for
	if(i<=l) 
	{
		R1[k++]=R[i++]; 	  
	}		
	if(j<=h)
	{
		R1[k++]=R[j++];         //將剩餘的R[j..h]複製到R1
	}
}//Merge

void Msort(RecType R[],RecType R1[],int s,int t)
{
	//將R[s..t]2-路歸併排序爲R1[s..t]
	RecType R2[100];
	if (s==t)
	{
		R1[s]=R[s];
	}
	else
	{
		int m=(s+t)/2;          //將R[s..t]平分爲R[s..m]和R[m+1..t]
		Msort(R,R2,s,m);        //遞歸的將R[s..m]歸併爲有序的R2[s..m]
		Msort(R,R2,m+1,t);      //遞歸的將R[m+1..t]歸併爲有序的R2[m+1..t]
		Merge(R2,R1,s,m,t);     //將R2[s..m]和R2[m+1..t]歸併到R1[s..t]
	}//if
}//Msort

int _tmain()
{
	int n;
	cout<<"MergingSort.cpp運行結果:\n";
	int b[100],i;
	RecType R1[100];
	srand(time(0));
	cout<<"輸入待排序元素個數n:";cin>>n;
	RecType SL[100];
	for(i=1;i<=n;i++)
	{
		b[i]=rand()%100;
		SL[i].key=b[i];
	}
	cout<<"排序前數組:\n";
	for(i=1;i<=n;i++)
		cout<<setw(4)<<b[i];
	cout<<endl;
	Msort(SL,R1,1,n);
	cout<<"排序後數組:\n";
	for(i=1;i<=n;i++)
		cout<<setw(4)<<R1[i].key;
	cout<<endl;
	system("pause");   
}


 

 

1.5 分配排序

      前面討論的排序算法都是基於關鍵字之間的比較,經過比較判斷出大小,而後進行調整。而分配排序則否則,它是利用關鍵字的結構,經過「分配」和「收集」的辦法來實現排序。

      分配排序:經過對無序序列中的記錄進行反覆的「分配」和「收集」操做,逐步是無序序列變爲有序序列。

分配排序分爲:桶排序和基數排序兩類。

計數排序

      

計數排序的過程相似小學選班幹部的過程,如某某人10票,做者9票,那某某人是班長,做者是副班長

大致分兩部分,第一部分是拉選票和投票,第二部分是根據你的票數入桶

看下具體的過程,一共須要三個數組,分別是待排數組,票箱數組,和桶數組

var unsorted = new int[] { 6, 2, 4, 1, 5, 9 };  //待排數組

var ballot = new int[unsorted.Length];          //票箱數組

var bucket = new int[unsorted.Length];          //桶數組

最後再看桶數組,先看待排數組和票箱數組

初始狀態,迭代變量i = 0時,待排數組[i] = 6,票箱數組[i] = 0,這樣經過迭代變量創建了數字與其桶號(即票數)的聯繫

待排數組[ 6 2 4 1 5 9 ] i = 0時,能夠從待排數組中取出6

票箱數組[ 0 0 0 0 0 0 ] 同時能夠從票箱數組裏取出6的票數0,即桶號

拉選票的過程

首先6出列開始拉選票,6的票箱是0號,6對其它全部數字說,誰比我小或與我相等,就給我投票,否則揍你

因而,2 4 1 5 分別給6投票,放入0號票箱,6得四票

待排數組[ 6 2 4 1 5 9 ]

票箱數組[ 4 0 0 0 0 0 ]

 

接下來2開始拉選票,對其它人說,誰比我小,誰投我票,否則弄你!因而1投了一票,其餘人比2大不搭理,心想你可真二

因而2從1那獲得一票

待排數組[ 6 2 4 1 5 9 ]

票箱數組[ 4 1 0 0 0 0 ]

 

再而後是,

4獲得2和1的投票,共計兩票

1獲得0票,沒人投他

5獲得2,4,1投的三張票

9是最大,獲得全部人(本身除外)的投票,共計5票(數組長度-1票)

 

投票完畢時的狀態是這樣

待排數組[ 6 2 4 1 5 9 ]

票箱數組[ 4 1 2 0 3 5 ]


入桶的過程

投票過程結束,每人都擁有本身的票數,桶數組說,看好你本身的票數,進入與你票數相等的桶,GO

6共計5票,進入5號桶

2得1票,進入1號桶,有幾票就進幾號桶

4兩票,進2號桶,5三票進3號桶,9有5票,進5號桶

待排數組[ 6 2 4 1 5 9 ]

票箱數組[ 4 1 2 0 3 5 ]

-----------------------

入桶前 [ 0 1 2 3 4 5 ] //裏邊的數字表示桶編號

入桶後 [ 1 2 4 5 6 9 ] //1有0票,進的0號桶

排序完畢,順序輸出便可[ 1 2 4 5 6 9]

 

能夠看到,數字越大票數越多,9獲得除本身外的全部人的票,5票,票數最多因此9最大,

每一個人最多擁有[數組長度減去本身]張票

1票數最少,因此1是最小的

 


 

#include "stdafx.h"
#include <iostream>
#include <cstdio> 
#include <cstdlib> 
#include <cmath> 
#include <cstring>
#include <stdlib.h>
#include<time.h>
#include<iomanip>
#include<math.h>

using namespace std; 

void CountingSort(int *A,int *B,int *Order,int N,int K) 
{ 
	int *C=new int[K+1]; 
	int i; 
	memset(C,0,sizeof(int)*(K+1)); 
	for (i=1;i<=N;i++) //把A中的每一個元素分配 
		C[A[i]]++; 
	for (i=2;i<=K;i++) //統計不大於i的元素的個數 	
	{
		C[i]+=C[i-1];
	}
	for (i=N;i>=1;i--) 
	{ 
		B[C[A[i]]]=A[i]; //按照統計的位置,將值輸出到B中,將順序輸出到Order中 
		Order[C[A[i]]]=i; 
		C[A[i]]--; 
	} 
} 
int main() 
{ 
	int *A,*B,*Order,N=15,K=10,i; 
	A=new int[N+1]; 
	B=new int[N+1]; 
	Order=new int[N+1]; 
	for (i=1;i<=N;i++) A[i]=rand()%K+1; //生成1..K的隨機數 
	cout<<"Before CS:\n"; 
	for (i=1;i<=N;i++) 
		cout<<setw(4)<<A[i];
	cout<<endl;
	CountingSort(A,B,Order,N,K); 
	printf("\nAfter CS:\n"); 
	for (i=1;i<=N;i++) 
		cout<<setw(4)<<B[i];
	cout<<endl;
	cout<<"\nOrder:\n"; 
	for (i=1;i<=N;i++) 
		cout<<setw(4)<<Order[i];
	cout<<endl;
	system("pause");
	return 0; 
} 


運行結果:


 

 

桶排序

     桶排序(Bucket Sort)也稱箱排序(Bin Sort),其基本思想是:設置若干個桶,依次掃描待排序記錄R[1..n],把關鍵字等於k的記錄所有都裝到第k個桶裏(分配),按序號依次將各非空的桶首尾鏈接起來(收集)。桶的個數取決於關鍵字的取值範圍。

桶排序 (Bucket sort)或所謂的箱排序,是一個排序算法,工做的原理是將數組分到有限數量的桶子裏。
基本思路:
1.設置一個定量的數組看成空桶子。
2.尋訪串行,而且把項目一個一個放到對應的桶子去。
3.對每一個不是空的桶子進行排序。
4.從不是空的桶子裏把項目再放回原來的串行中。

 

無序數組有個要求,就是成員隸屬於固定(有限的)的區間,如範圍爲[0-9](考試分數爲1-100等)

例如待排數字[6 2 4 1 5 9]

準備10個空桶,最大數個空桶

[6 2 4 1 5 9]           待排數組

[0 0 0 0 0 0 0 0 0 0]   空桶

[0 1 2 3 4 5 6 7 8 9]   桶編號(實際不存在)

 

1,順序從待排數組中取出數字,首先6被取出,而後把6入6號桶,這個過程相似這樣:空桶[ 待排數組[ 0 ] ] = 待排數組[ 0 ]

[6 2 4 1 5 9]           待排數組

[0 0 0 0 0 0 6 0 0 0]   空桶

[0 1 2 3 4 5 6 7 8 9]   桶編號(實際不存在)

 

2,順序從待排數組中取出下一個數字,此時2被取出,將其放入2號桶,是幾就放幾號桶

[6 2 4 1 5 9]           待排數組

[0 0 2 0 0 0 6 0 0 0]   空桶

[0 1 2 3 4 5 6 7 8 9]   桶編號(實際不存在)

 

3,4,5,6省略,過程同樣,所有入桶後變成下邊這樣

[6 2 4 1 5 9]           待排數組

[0 1 2 0 4 5 6 0 0 9]   空桶

[0 1 2 3 4 5 6 7 8 9]   桶編號(實際不存在)

 

0表示空桶,跳過,順序取出便可:1 2 4 5 6 9

/* 桶排序實現 */ 
#include "stdafx.h"
#include <iostream>
#include <cstdio> 
#include <cstdlib> 
#include <cmath> 
#include <cstring>
#include <stdlib.h>
#include<time.h>
#include<iomanip>
#include<math.h>

using namespace std; 

void BucketSort(int *A,int *B,int N,int K) 
{ 
	int *C=new int[K+1]; 
	int i,j,k; 
	memset(C,0,sizeof(int)*(K+1)); 
	for (i=1;i<=N;i++) //把A中的每一個元素按照值放入桶中 
		C[A[i]]++; 
	for (i=j=1;i<=K;i++,j=k) //統計每一個桶元素的個數,並輸出到B 
		for (k=j;k<j+C[i];k++) 
			B[k]=i; 
}

int main() 
{ 
	int *A,*B,N=100,K=100,i; 
	A=new int[N+1]; 
	B=new int[N+1]; 
	cout<<"排序前:"<<endl;
	for (i=1;i<=N;i++) 
	{
		A[i]=rand()%K+1; //生成1..K的隨機數 
		cout<<setw(4)<<A[i];
	}	
	cout<<endl; 
	BucketSort(A,B,N,K);
	cout<<"排序後:"<<endl;
	for (i=1;i<=N;i++) 
	{
		cout<<setw(4)<<B[i];
	}
	cout<<endl;
	system("pause");  
	return 0; 
} 

運行結果:


 

這種特殊實現的方式時間複雜度爲O(N+K),空間複雜度也爲O(N+K),一樣要求每一個元素都要在K的範圍內。更通常的,若是咱們的K很大,沒法直接開出O(K)的空間該如何呢?
 
首先定義桶,桶爲一個數據容器,每一個桶存儲一個區間內的數。依然有一個待排序的整數序列A,元素的最小值不小於0,最大值不超過K。假設咱們有M個桶,第i個桶Bucket[i]存儲iK/M至(i+1)K/M之間的數,有以下桶排序的通常方法:
 1.掃描序列A,根據每一個元素的值所屬的區間,放入指定的桶中(順序放置)。
 2.對每一個桶中的元素進行排序,什麼排序算法均可以,例如快速排序。
 3.依次收集每一個桶中的元素,順序放置到輸出序列中。
 
對該算法簡單分析,若是數據是指望平均分佈的,則每一個桶中的元素平均個數爲N/M。若是對每一個桶中的元素排序使用的算法是快速排序,每次排序的時間複雜度爲O(N/Mlog(N/M))。則總的時間複雜度爲O(N)+O(M)O(N/Mlog(N/M)) = O(N+ Nlog(N/M)) = O(N + NlogN - NlogM)。當M接近於N是,桶排序的時間複雜度就能夠近似認爲是O(N)的。就是桶越多,時間效率就越高,而桶越多,空間卻就越大,因而可知時間和空間是一個矛盾的兩個方面。

 

/*桶排序實現 */ 
#include "stdafx.h"
#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cmath> 
#include <cstring> 
#include <stdlib.h>
#include<time.h>
#include<iomanip>
#include<math.h>

using namespace std; 
struct linklist 
{ 
	linklist *next; 
	int value; 
	linklist(int v,linklist *n):value(v),next(n){} 
	~linklist() {if (next) delete next;} 
}; 
inline int cmp(const void *a,const void *b) 
{ 
	return *(int *)a-*(int *)b; 
} 
/* 爲了方便,我把A中元素加入桶中時是倒序放入的,而收集取出時也是倒序放入序列的,因此不違背穩定排序。 */ 

void BucketSort(int *A,int *B,int N,int K) 
{ 
	linklist *Bucket[101],*p;
	//創建桶 
	int i,j,k,M; M=K/100; 
	memset(Bucket,0,sizeof(Bucket)); 
	for (i=1;i<=N;i++) 
	{ 
		k=A[i]/M; 
	//把A中的每一個元素按照的範圍值放入對應桶中 
		Bucket[k]=new linklist(A[i],Bucket[k]); 
	} 
	for (k=j=0;k<=100;k++) 
	{ 
		i=j; 
		for (p=Bucket[k];p;p=p->next) 
			B[++j]=p->value; 
		//把桶中每一個元素取出,排序並加入B 
		delete Bucket[k]; 
		qsort(B+i+1,j-i,sizeof(B[0]),cmp); 
	} 
} 
int main() 
{ 
	int *A,*B,N=100,K=100,i; 
	A=new int[N+1]; 
	B=new int[N+1]; 
	for (i=1;i<=N;i++) 
	{
		A[i]=rand()%K+1; //生成1..K的隨機數 
		cout<<setw(4)<<A[i];
	}	
	cout<<endl; 
	BucketSort(A,B,N,K);
	cout<<"排序後:"<<endl;
	for (i=1;i<=N;i++) 
	{
		cout<<setw(4)<<B[i];
	}
	cout<<endl;
	system("pause"); 
	return 0; 
} 

運行結果:

 

基數排序

     基數排序(Radix Sort)是對桶排序的改進和推廣。

     基本思想:將一個關鍵字分解成多個「關鍵字」,再利用多關鍵字排序的思想對記錄序列進行排序。基數排序就是藉助「多關鍵字排序」的思想來實現「單關鍵字排序」的算法。

     假設有n個記錄的待排序序列{R1,R2,...,Rn},每一個記錄Ri中含有d個關鍵字,則稱上述記錄序列對關鍵字有序,是指對於序列中的任意兩個記錄Ri和Rj(1<=i<j<=n)都知足下列(詞典)有序關係;

具體作法爲:

     (1)待排序的記錄以指針相鏈,構成一個鏈表。

     (2)「分配」時,按當前「關鍵字位」的取值,將記錄分配到不一樣的「鏈隊列」中,每一個隊列中記錄的「關鍵字位」相同。

     (3)「收集」時,按當前關鍵字取值從小到大將各隊首尾相連接成一個鏈表;對每一個關鍵字位均重複2)和3)兩步。以下所示:

p->369->367->167->239->237->138->230->139

第一次分配獲得:

B[0].f->230<-B[0].e

B[7].f->367->167->237<-B[7].e

B[8].f->138<-B[8].e

B[9].f->369->239->139<-B[9].e

第一次收集獲得:

p->230->367->167->237->138->369->239->139

第二次分配獲得:

B[3].f->230->237->138->239->139<-B[3].e

B[6].f->367->167->369<-B[6].e

第二次收集獲得:

p->230->237->138->239->139->367->167->369

第三次分配獲得:

B[1].f->138->139->167<-B[1].e

B[2].f->230->237->239<=B[2].e

B[3].f->367->369<-B[3].e

第三次收集以後便獲得記錄的有序序列:

p->138->139->167->230->237->239->367->369


 

#include "stdafx.h"
#include <iostream>  
#include<stdlib.h>  
#include<iomanip>  
#include<math.h>  

using namespace std;  

int maxbit(int data[],int n) //輔助函數,求數據的最大位數

{

	int d = 1; //保存最大的位數

	int p =10;

	for(int i = 0;i < n; ++i)

	{

		while(data[i] >= p)

		{

			p *= 10;

			++d;

		}

	}

	return d;

}

void radixsort(int data[],int n) //基數排序

{

	int d = maxbit(data,n);

	int * tmp = new int[n];

	int * count = new int[10]; //計數器

	int i,j,k;

	int radix = 1;

	for(i = 1; i<= d;i++) //進行d次排序

	{

		for(j = 0;j < 10;j++)

			count[j] = 0; //每次分配前清空計數器

		for(j = 0;j < n; j++)

		{

			k = (data[j]/radix)%10; //統計每一個桶中的記錄數

			count[k]++;

		}

		for(j = 1;j < 10;j++)

			count[j] = count[j-1] + count[j]; //將tmp中的位置依次分配給每一個桶

		for(j = n-1;j >= 0;j--) //將全部桶中記錄依次收集到tmp中

		{

			k = (data[j]/radix)%10;

			tmp[count[k]-1] = data[j];

			count[k]--;

		}

		for(j = 0;j < n;j++) //將臨時數組的內容複製到data中

			data[j] = tmp[j];

		radix = radix*10;

	}

	delete [] tmp;

	delete [] count;

}

int _tmain(int argc, _TCHAR* argv[])  
{  
	int data[10]={267,6,9,679,0,999,99,9,22,11};  
	std::cout<<"初始序列"<<endl;  
	for(int j=0;j<10;j++)    
	{      
			std::cout <<setw(4)<< data[j];     
	}  
	std::cout<<endl;  
	radixsort( data,10);  
	std::cout<<"生成的有序序列"<<endl;  
	for(int j=0;j<10;j++)    
	{      
		 std::cout << setw(4)<<data[j];     
	}  
	std::cout<<endl;  
	system("pause");  system("pause");      
	return 0;  
}  


 運行結果:

各類排序算法比較

 

排序法 平均時間 最差情形 穩定度 額外空間 備註
冒泡 O(n2)     O(n2) 穩定 O(1) n小時較好
交換     O(n2)     O(n2) 不穩定 O(1) n小時較好
選擇 O(n2) O(n2) 不穩定 O(1) n小時較好
插入 O(n2) O(n2) 穩定 O(1) 大部分已排序時較好
基數 O(logRB) O(logRB) 穩定 O(n)

B是真數(0-9),

R是基數(個十百)

Shell O(nlogn) O(ns) 1<s<2 不穩定 O(1) s是所選分組
快速 O(nlogn) O(n2) 不穩定 O(nlogn) n大時較好
歸併 O(nlogn) O(nlogn) 穩定 O(1) n大時較好
O(nlogn) O(nlogn) 不穩定 O(1) n大時較好


 

2 外部排序

外部排序:若參加排序的記錄數量很大,整個排序過程不能一次在內存中完成,則稱此類排序問題爲外部排序;

 

 

 

 

      以上博客,若有參考使用,請標明出處;

 

參考:

 《算法與數據結構》 第二版   陳守孔 著

參考的網上內容:

http://blog.csdn.net/onedreamer/article/details/6745006
http://blog.csdn.net/zhangkaihang/article/details/7394806
http://blog.csdn.net/yincheng01/article/category/1269370/1
http://blog.csdn.net/yincheng01/article/details/8205037
http://www.chinadmd.com/file/wt63reerwwo6wcpxeiv3twx6_1.html
https://www.byvoid.com/blog/sort-radix
http://www.cnblogs.com/kkun/archive/2011/11/23/2260299.html
http://www.cnblogs.com/kkun/archive/2011/11/23/2260267.html
http://blog.csdn.net/hkx1n/article/details/3922249

相關文章
相關標籤/搜索