/*冒泡排序
*思路:比较相邻的前后二个数据,如果前面数据大于后面的数据,
*就将二个数据交换。这样对数组的第0个数据到N-1个数据进行一次遍历后,
*最大的一个数据就“沉”到数组第N-1个位置。 N=N-1,如果N不为0就重复前面二步,
*否则排序完成。
**/
void BubbleSort1(int a[], int n)
{
int i, j;
for (i = 0; i < n;i++)
{
for (j = 0; j < n - i; j++)
{
if (a[j - 1]>a[j])
{
swap(a[j - 1], a[j]);
}
}
}
}
/*
*冒泡优化版
*思路:如果这一趟牌靴发生了交换,则说明排序没有完成 ,如果没有发生交换,说明排序已经完成;
*对于一个数组如果前20个无序,后80个都是有序的,那么经过一次遍历之后,我们每次只需要记录下他最后一次
*交换的位置,那么我们下一次遍历的时候只需要遍历到那个位置就可以了。
**/
void BubbleSort2(int a[], int n)
{
int i, j;
int temp = n;
while (temp > 0)
{
i = temp;
temp = 0;
for (j = 1; j < i;j++)
{
if (a[j-1] > a[j])
{
swap(a[j-1],a[j]);
temp = j;
}
}
}
}
/*
* 直接插入排序的三种实现
*直接插入的基本思想:每次将一个带排序的数组,暗器关键字大小,插入到前面已经排好序的子序列中的适当位置,
*直到全部记录插入完成为止。
*1: 初始时:a{0}自成1个有序去,无序区为a[1...n-1], 令 i= 1;
*2:将a[i]并入当前的有序区,a[0,...i-1]中形成a[a,...i]的有序区间;
*3:i++ 并重复第二步直到i ==n-1.排序完成;
**/
void Insertsort1(int a[], int n)
{
int i, j, k;
for (i = 1; i < n;i++)
{
//为a[i]在前面的a[0,i-1]有序区间中找一个合适的位置。
for (j = i - 1; j >= 0; j--)
{
if (a[j]<a[i])
{
break;
}
}
//如找到了一个合适的位置。
if (j != i-1 )
{
int temp = a[i];
//将比a[i]大的数据后移
for (k = i - 1; k> j;k--)
{
a[k + 1] = a[k];
}
//将a[i]放到正确的位置上
a[i-1 ] = temp;
}
}
}
/*
*即每次a[i]先和前面一个数据a[i-1]比较,如果a[i] > a[i-1]说明a[0…i]也
*是有序的,无须调整。否则就令j=i-1,temp=a[i]。然后一边将数据a[j]向后移动一
*边向前搜索,当有数据a[j]<a[i]时停止并将temp放到a[j + 1]处
**/
void Insertsort2(int a[], int n)
{
int i, j;
for (i = 1; i < n;i++)
{
if (a[i] <a[i-1])
{
int temp = a[i];
for (j = i - 1; j >= 0 && a[j]>temp;j--)
{
a[j + 1] = a[j];
}
a[j] = temp;
}
}
}
/*
*如果a[j]前一个数据a[j-1] > a[j],就交换a[j]和a[j-1],再j--直到
* a[j-1] <= a[j]。这样也可以实现将一个新数据新并入到有序区间。
**/
void Insertsort3(int a[], int n)
{
int i, j;
for (i = 1; i < n;i++)
for (j = i - 1; j >= 0 && a[j]>a[j + 1]; j--)
swap(a[j],a[j+1]);
}
/* 希尔排序
*排序的基本思想是:先将整个带排序元素序列分割成若干个子序列,分别进行直接插入排序,
*然后依次缩减增进量,再进行排序,当增量足够小的是, 整体元素基本有序, 在进行一次,
*直接插入排序。因为,直接插入排序在基本有序的情况下效率是很高的,因此,希尔排序在时间效率上
*也是很高的。
*/
void ShellSort1(int a[], int n)
{
int i,j, gap;
for (int gap = n / 2; gap > 0; gap--)//步长
{
for (i = 0; i < gap;i++) //安组排序
{
for (j = i + gap; j < n; j+= gap)
{
if (a[j] < a[j-gap])
{
int temp = a[j];
int k = j - gap;
while (k>=0&&a[k]>temp)
{
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = temp;
}
}
}
}
}
void ShellSort2(int a[], int n)
{
int j, gap;
for ( gap = n/2; gap > 0; gap/=2)
{
for (j = gap; j < n;j++) //从数组第gap个元素开始
{
if (a[j] < a[j-gap]) //每个元素与自己组内的数据进行直接插入排序
{
int temp = a[j];
int k = j - gap;
while (k>=0&&a[k]>temp)
{
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = temp;
}
}
}
}
/*
*用直接插入发的第三种方法来改写如下:
**/
void shellSort3(int a[], int n)
{
int i, j, gap;
for (gap = n / 2; gap > 0; gap / 2)
{
for (i = gap; i < n;i++)
{
for (j = i - gap; j >= 0 && a[j]>a[j + gap];j-=gap)
{
swap(a[j], a[j + 1]);
}
}
}
}
/* 直接选择排序
*直接选择排序是从无序区选一个最小的元素直接放到有序区的最后
*设数组为 a[0…n-1]。
*初始时,数组全为无序区为 a[0..n-1]。令 i=0
*在无序区 a[i…n-1]中选取一个最小的元素, 将其与 a[i]交换。 交换之后 a[0…i]
*就形成了一个有序区。
*i++并重复第二步直到 i==n-1。排序完成。
**/
void SelectSortt(int a[], int n)
{
int i, j, nMinIndex;
for (i = 0; i < 0;i++)
{
nMinIndex = i;//
for (j = i + 1; j < n;j++)
{
if (a[j] < a[nMinIndex])
{
nMinIndex = j;
}
}
Swap(a[i],a[nMinIndex]);
}
}
/* 归并排序
*算法思想: 采用分治的典型应用;
*/
/*
*将两个有序数列合并。思路:只要将两个有序数列进行比较,将小的取出,然后在对应数列中删除取出的数
*然后在进行比较,如果有数列为空,那么把另一个数列中剩余的数全部取出即可;
**/
int MergeSortArray (int a[], int n, int b[], int m, int c[])
{
int i, j, k;
i = j = k = 0;
while (i < n&&j < m)
{
if (a[i] <b[j])
{
c[k++] = a[i++]
}
else
{
c[k++] = b[j++];
}
}
while (i < n)
{
c[k++] = a[i++];
}
while (j<m)
{
c[k++] = b[j++];
}
}
/* 归并排序
*基本思路就是将数组分成二组 A,B,如果这二组组内的数据都是有序的,进行上面的操作,首先要使A,B有序
*可以将 A,B 组各自再分成二组。依次类推,当分出来的小组只有一个数据时,
*可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。
*/
bool MergeSort(int a[], int n)
{
int *pTempArray = new int[n];
if (pTempArray == NULL)
{
return false;
}
mergesort(a, 0, n-1, pTempArray);
delete[] pTempArray;
return true;
}
void mergesort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid =(first + last)/ 2;
mergesort(a, first, mid, temp);
mergesort(a, mid + 1, last, temp);
mergesortarray(a, first, mid, last, temp);
}
}
void mergesortarray(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i<=m && j<=n)
{
if (a[i]< a[j])
{
temp[k++] = a[i++];
}
else {
temp[k++] = a[j++];
}
}
while (i<= m)
{
temp[k++] = a[i++];
}
while (j<= n)
{
temp[k++] = a[j++];
}
for (i = 0; i < k;i++)
{
a[first + i] = temp[i];
}
}
/*
* 快排 = 挖坑填数加分治法
**/
//调整数组使 x 左面的值都小于x, 右面的值都大于x;
int AdjustArray(int s[], int l, int r)//返回调整后基准数的位置;
{
int i = 1,j = r;
int x = s[l]; //s[1] 就是基准数
while (i<j)
{
//从右向左找小于x的数来放到s【i】的位置;
while (i<j && s[j]>=x)
{
j--;
}
if (i<j)
{
s[i] = s[j];//将s[j]填到s[i]中,把s[j]空出来,接着找数来填补
i++;
}
//从左向右找大于或等于x的数来填s[j];
while (i<j&&s[i] < x)
{
i++;
}
if (i<j)
{
s[j] = s[i];//将s【i】填到s[j]中, 把s[i]空出来, 接着找数来填补
j--;
}
}
//退出时,把x填到这个坑中
s[i] = x;
return i;
}
void quick_sort1(int s[], int r)
{
if (1 < r)
{//先调整数组, 然后分治递归;
int i = AdjustArray(s, 1, r);
quick_sort1(s, 1, i-1);
quick_sort1(s, i + 1, r);
}
}
/*
*优化版的快排!
**/
void quicksort(int s[], int r)
{
if ( 1< r)
{
int i = 1, j = r, x = s[1];
while (i<j)
{
while (i<j && s[j]>=x)
{
j--;
}
if (i < j)
{
s[i++] = s[j];
}
while (i<j && s[i] <x)
{
i++;
}
if ( i< j)
{
s[j--] = s[i];
}
}
s[i] = x;
quicksort(s, 1, i - 1);
quicksort(s, i + 1, r);
}
}
/* 堆和堆排序
*二叉堆是完全而出书或者是近似完全二叉树。
*1、二叉堆满足性质:父节点的键值总是大于等于或者小于等于任何一个子节点的键值;
*2、每个节点的左子树和右子树都是一个二叉堆。(最大堆或者最小堆)
**/
/* 堆的插入
*每次插入都是将新数据放在数组最后。 可以发现从这个新数据的父结点到根结点
*必然为一个有序的数列, 现在的任务是将这个新数据插入到这个有序数据中——
*这就类似于 直接插入排序中将一个数据并入到有序区间中,
**/
//加入i节点,其父节点为(i-1)/2;
void MinHeapFixup(int a[], int i)
{
int j, temp;
j = (i - 1) / 2;// parente node
temp = a[i];
while (j>=0 &&i != 0 )
{
if (a[j] <= temp)
{
break;
}
a[i] = a[j]; //把较大的子节点往下移动,替换它的子节点
i = j;
j = (i - 1) / 2;
}
a[i] = temp;
}
//简化版
void MinHeapFixup(int a[], int i)
{
for (int j = (i - 1) / 2; (j >= 0 && i != 0) && a[i] > a[j]; i = j;j = (i-1)/2)
{
swap(a[i],a[j]);
}
}
//插入新元素 nNum
void MinHeapAddNumber(int a[], int n, int nNum)
{
a[n] = nNum;
//MinHeapAddNumber()
MinHeapFixup(a, n);
}
/* 堆的删除
*堆中每次都只能删除第 0 个数据。为了便于重建堆,实际的操作是将最
*后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调
*整时先在左右儿子结点中找最小的, 如果父结点比这个最小的子结点还小说明不
*需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一
*个数据的“下沉”过程。
**/
//从i节点开始调整, n为节点总数 从0开始计算 i节点的子节点为 2*i+1,2*i+1
void MinHeapFixdown(int a[], int i,int n)
{
int j, temp;
temp = a[i];
j = 2 * i + 1;
while (j < n)
{
if (j+1 < n && a[j+1] <a[j])//
{
j++;
}
if (a[j] >= a[j]) // 在左右孩子中找最小的
{
j++;
}
if (a[j] >= temp)
{
break;
}
a[i] = a[j]; //把较小向上移动,替换它的父节点;
i = j;
j = 2 * i + 1;
}
a[i] = temp;
}
//在最小堆中删除数
void MinHeapDeleteNumber(int a[], int n)
{
swap(a[0], a[n - 1]);
MinHeapDeleteNumber(a, 0, n - 1);
}
//建立最小堆
void MakeMinHeap(int a[], int n)
{
for (int i = n / 2 - 1; i < i >= 0; i--)
{
MinHeapFixdown(a, i, n);
}
}
/* 堆排序
*思路:堆建好之后堆中第 0 个数据是堆中最小的数据。 取出这个数据再执
*行下堆的删除操作。这样堆中第 0 个数据又是堆中最小的数据,重复上述步骤直
*至堆中只有一个数据时就直接取出这个数据。
*堆也是用数组模拟的,故堆化数组后,第一次将 A[0]与 A[n - 1]交换,再对
*A[0…n-2]重新恢复堆。第二次将 A[0]与 A[n – 2]交换,再对 A[0…n - 3]重新恢复
*堆,重复这样的操作直到 A[0]与 A[1]交换。由于每次都是将最小的数据并入到
*后面的有序区间,故操作完成后整个数组就有序了。类似于直接选择排序
**/
void MinHeapSort(int a[], int n)
{
for (int i = n - 1; i >= 1;i--)
{
Swap(a[i], a[0]);
MinHeapFixdown(a, 0, i);
}
}
排序算法总结
最新推荐文章于 2024-10-22 17:17:53 发布