一 前言
八種排序算法的關係:
二 插入排序
插入排序基本思想:按照關鍵字的大小將一個關鍵字插入到一個有序序列的文件的適當位置,並且使插入後的文件仍然是有序的。在插入的時候,尋找合適的位置可以採用順序查找法,折半查找法等其他方法,相應的插入排序有:直接插入排序,折半插入排序,希爾排序。
結點定義:
template<class T>
class node
{
friend class list < T >;
public:
node():index(0){}
~node(){}
T getdata()
{
return data;
}
private:
T data;
};
表定義:
template<class T>
class list
{
template<class T>
friend std::ostream& operator<<(std::ostream& out, list<T>& lst);
public:
list() :maxsize(0), currsize(0){}
list(int ms) :maxsize(ms) //產生一序列數
{
vec = new node < T >[maxsize];
std::cout << "please input" << maxsize << " numbers" << std::endl;
// vec[maxsize] = {0};
T num;
int i = 0;
while (cin >> num)
{
if (i < maxsize)
{
vec[i].data = num;
++i;
++currsize;
}
}
}
~list()
{
delete[] vec;
}
public:
void Insertsort();
void Binarysort();
void Shellsort();
private:
node<T>* vec;
int maxsize;
int currsize;
};
1.直接插入排序
基本思想:當插入第n個(n>1)個對象時候,假設前面(n-1) 個對象已經是排好順序的,現在要把第n個數插到前面的有序數中,用第n個對象的關鍵值與第n-1,n-2...的順序逐一進行比較,直至找到插入的位置插入。
核心:找位置,看過一篇博客說把找位置比喻成“找坑”,找到一個比自己大的數,就用那個位置的土把自己前面一個的坑給填上,直至遇到比自己小的 數(循環結束),用要插入的值把最合適的坑填上。
方法一:
template<class T>
void list<T>::Insertsort() //直接排序法
{
int j,k;
for (int i = 1; i < currsize; ++i)
{
for (j = i - 1; j >= 0; --j) //與前n-1個數中相比較,找到插入位置
if (vec[i].data >= vec[j].data) //找到位置
break;
if (j != i - 1) //找到插入位置後,就要移動數據;如果j==i-1,就不需要移動數據
{
node<T>* temp=new node<T>;
temp->data= vec[i].data;
for (k = i-1; k>j; --k)
vec[k+1].data = vec[k].data;
vec[k+1].data= temp->data; //插入數據
delete temp;
temp = nullptr;
}
}
}
方法二:
template<class T>
void list<T>::Insertsort() //直接排序法
{
for (int i = 1; i < currsize; ++i) //排序
{
node<T> temp = vec[i];
int j = i;
while (j>0 && (temp.data < vec[j - 1].data)) //找到要插入的位置
{
vec[j].data = vec[j - 1].data;
--j;
}
vec[j].data = temp.data;
}
}
2.折半插入排序
基本思想:當插入第n個(n>1)個對象時候,假設前面(n-1) 個對象已經是排好順序的,現在要把第n個數插到前面的有序數中,利用”折半查找法“來查找插入的位置。
template<class T>
void list<T>::Binarysort() //折半插入排序法
{
for (int i = 1; i < currsize; ++i)
{
int left = 0; int right = i - 1;
node<T>* temp = new node < T > ;
temp->data=vec[i].data;
int j = i;
while (left <= right) //找到插入位置
{
int middle = (left + right) / 2;
if (temp->data < vec[middle].data)
right = middle - 1;
else
left = middle + 1;
}
for (int k = i - 1; k >= left; --k) //移動數據
vec[k + 1].data = vec[k].data;
vec[left].data = temp->data;
delete temp;
temp = nullptr;
}
}
3.希爾排序
基本思想:不斷的把待排序的一組數據按間隔值分成若干小組,然後對同一組的數據進行排序。
基本操作:設待排序列有n個對象,首先取一個整數gap作爲間隔,將全部序列分成gap個子序列,所有距離爲gap的對象放在同一個子序列中,每個子序列分別進行直接插入排序,然後逐漸縮小gap,直至gap=1.將所有的序列放入同一組中。
template<class T>
void list<T>::Shellsort() //希爾排序
{
int gap = currsize / 2;
while (gap) //循環到間隔gap=0
{
for (int i = gap; i < currsize; ++i) //對各個子序列進行排序
{
node<T> temp;
temp.data = vec[i].data;
int j = i;
while (j >= gap&&temp.data < vec[j - gap].data) //與前面一個元素進行比較
{
vec[j].data = vec[j - gap].data;
j = j - gap;
}
vec[j].data = temp.data;
}
if (gap == 2) //當間隔爲2的排序結束後,將gap=1
{
gap = 1;
}
else
{
gap = (int)gap / 2.2;
}
}
}
補充: Java版本
// 直接插入排序法
public int[] insertSort(int[] arr){
int size = arr.length;
int i = 0, j = 0;
if(size > 0){
for(i = 1;i < size;++i){
if(arr[i - 1] > arr[i]){
int temp = arr[i]; // 保存較小的值
// 對前 i-1 個數再進行排序
for(j = i-1; j >= 0 && arr[j] >= temp; --j){
arr[j+1] = arr[j];
}
arr[j+1] = temp;
}
}
}
return arr;
}
// 折半插入排序法
public int[] binarySort(int[] arr){
int size = arr.length;
if(size > 0){
// 想插入第n個數,假設前n-1個爲有序的
for(int i = 1; i < size ; ++i){
int left = 0, right = i - 1;
//要插入的數
int temp = arr[i];
// 尋找插入的位置
while(right >= left){
int mid = (right + left)/2;
if(arr[mid] > arr[i])
right = mid - 1;
else
left = mid + 1;
}
// 移動數據
for(int k = i;k > left; --k){
arr[k] = arr[k-1];
}
arr[left]=temp;
}
}
return arr;
}
// 希爾排序
public int[] shellSort(int[] arr){
// 希爾排序就是根據間隔gap將序列分成幾組分別利用直接插入排序法排序,直至gap爲1
int size = arr.length;
int gap = size/2; // 初始gap
while(gap >= 1){
for(int i = gap; i < size; ++i){
int temp = arr[i];
int j = 0;
for(j = i; j >= gap && arr[j - gap] > temp; j=j-gap){
arr[j] = arr[j-gap];
}
arr[j] = temp;
}
if(gap == 2){
gap = 1;
} else {
gap = (int) (gap / 2.2);
}
}
return arr;
}