冒泡排序:
思想:从左端开始两个数两个数的(相邻的两个数)开始进行比较,第一次先求出n个数中最小的数,放在下标为1的位置。爹日次开始从下标为2的位置来时,也是两个数(相邻的两个数开始比较)。比较出n-1个数里面最小的那个数放在下表是2的位置哪里。一次类推。
for(int i=0 ; i<num.length ; i++){
for(int j=0 ; j<num.length-i-1 ; j++){
if(num[j]>num[j+1]){
int temp = num[j];
num[j] = num[j+1];
num[j+1] = temp;
}
}
}
选择性排序:
思想:先找出数列的最小值,将这个所在的元素位置和第一个数相交换,如果最小值本来就在最左端了那就不用操作了。然后从第二个位置开始,再找出最小值和第二个数相交换。以此类推(记住是交换不是直接赋值)
int a[]= {3,4,2,6,4,11,8,7};
for (int i=0; i<8-1; i++)
{
int flag=i;
for (int j=i+1; j<8; j++)
{
if (a[j] < a[flag])
{
flag=j;
}
}
int temp = a[flag];
a[flag] = a[i];
a[i] = temp;
}
插入排序:
直接插入排序的思想是,把一个无序的数组插入到有序的数组里面就会产生一个有序的数组,那么为了空间的合理利用,以及复杂度,所以不会单独开一块数组空间,而是把本数组的第一个数看作一个有序数组。所以这就有了下面的话。
思想:(直接插入排序)插入排序先第一步固定左边第一个数(已操作的数),然后从第二个数(未操作的数)开始和已经操作的数比较要是小的话(第二个数也变为已操作的数了),就互换位置。然后第三个数开始继续和已操作的数比较,一个一个的向前比较,直到遇见比自己小的数就停下来。以此类推。
int a[]={3,4,2,6,4,11,8,7};
for(int i=1;i<8;i++)
{
for(int j=0;j<i;j++)
{
if(a[i]<a[j])
{
int temp=a[j];
a[j]=a[i];
a[i]=temp;
}
}
}
堆排序:
思想:(这里只讲排序不讲堆)首先前提条件是:1.完全二叉树。2.父亲节点要大于子节点(大顶堆,小顶堆的话就是反过来的)。二叉树可以用数组来维护,所以堆也是 如此。然后堆的操作是这样的:如果父亲节点和子节点相比较的话,要是小的话那就要交换。(要是两个子节点都比父节点要来的大的话,那和谁交换呢)和最大的子节点交换。ddd=大顶堆
void ddd(int arr[],int i,int size){
if(i<size){
int left=2*i+1;
int right=2*i+2;
int largest=i;
if(left<size){
if(arr[largest]<arr[left]){
largest=left;
}
}
if(right<size){
if(arr[largest]<arr[right]){
largest=right;
}
}
if(largest!=i){
int temp=arr[largest];
arr[largest]=arr[i];
arr[i]=temp;
ddd(arr,largest,size);
}
}
}
归并排序:
思想:这里用的递归方法。首先归并排序和归并操作脱不了干系。先将当前的数组分成两个数组,然后将两个排好顺序的数组合并为一个序列。(口笨,不知道怎么表达)这就是归并排序了。直接上代码
void merge(int arr[], int left, int mid, int right)
{
int n1 = mid - left + 1; //leftPart数组的长度; [left,mid]
int n2 = right - mid; //rightPart数组的长度 [mid+1,right];
int *leftPart = new int[n1];
int *rightPart = new int[n2];
//复制到左右两边
for(int i = 0; i < n1; i++)
{
leftPart[i] = arr[left + i];
}
for(int i = 0; i < n2; i++)
{
rightPart[i] = arr[mid + i + 1]; //mid在左边
}
//左右两部分合并
int i = 0, j = 0, k = left;
while(i < n1 && j < n2)
{
if(leftPart[i] <= rightPart[j])
{
arr[k++] = leftPart[i++];
}
else
{
arr[k++] = rightPart[j++];
}
}
while(i < n1)
{
arr[k++] = leftPart[i++];
}
while(j < n2)
{
arr[k++] = rightPart[j++];
}
delete [] leftPart;
delete [] rightPart;
}
void mergeSort(int arr[],int left, int right)
{
if(left < right)
{
int mid = left + ((right - left)>>1);
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
快排:
快排至少有三种以上的写法,这里我讲左右指针法,区别在于我交换的是左右指针的位置,而不是和基准数的位置(挖坑法)
思想:举个例子,有这么一个数组:6,1,2,7,9,3,4,5,10,8。那么现在我要对这个数组利用快排进行排序,使得数组是有序的。
根据快排的思想,首先要找到一个基准数,我们一般用第一个数作为基准数,那么现在再设立左边和右边的两个指针,首先i指向6,j指向8。
那么现在j指针开始向右边移动,这时候j指针要去找比6小的数(5),找到之后呢,i开始向左边移动,找大于基准数的数(7),找到之后i,j位置上的数相交换(和挖坑不一样)。这时候数据变为:6,1,2,5,9,3,4,7,10,8。以此类推一直找下去之后当i,j碰到一起的时候,把i,j共同位置上面的数据和基准数据做一个交换,所以最后的数据是这样子的:3,1,2,5,4,6,9,7,10,8
所以呢,这时候我们就达到目的了,比基准数小的都在左边,比基准数大的都在右边。
那么现在继续,再左边的区间里面其实数据还是混乱的,那么就再左边的区间里面再一次实现第一次的比较
(3,1,2,5,4)。右边也一样,一次类推一直校验下去(所以是会用到递归的)
上代码:
#include <stdio.h>
int a[101],n;//定义全局变量,这两个变量需要在子函数中使用
void quicksort(int left, int right) {
int i, j, t, temp;
if(left > right)
return;
temp = a[left]; //temp中存的就是基准数
i = left;
j = right;
while(i != j) { //顺序很重要,要先从右边开始找
while(a[j] >= temp && i < j)
j--;
while(a[i] <= temp && i < j)//再找右边的
i++;
if(i < j)//交换两个数在数组中的位置
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//最终将基准数归位
a[left] = a[i];
a[i] = temp;
quicksort(left, i-1);//继续处理左边的,这里是一个递归的过程
quicksort(i+1, right);//继续处理右边的 ,这里是一个递归的过程
}
int main() {
int i;
//读入数据
scanf("%d", &n);
for(i = 1; i <= n; i++)
scanf("%d", &a[i]);
quicksort(1, n); //快速排序调用
//输出排序后的结果
for(i = 1; i < n; i++)
printf("%d ", a[i]);
printf("%d\n", a[n]);
return 0;
}