数据结构之排序

直接插入排序:
算法:1,将序列中的第1个记录看成是有序的子序列
2。从第二个记录起按关键字大小逐个进行插入,直至整个序列变成按关键字有效序列为止
(1)稳定性
直接插入排序是稳定的排序方法。
(2)算法效率
a.时间复杂度
最好情况:比较O(n),移动O(1);
最坏情况:比较O(n2),移动O(n2);
平均O(n2)
b.空间复杂度
O(1)。

#include<stdio.h>

//直接插入排序
void InsertionSort(int l[],int len)
{
	int i, j;
	for (i = 1; i <len; ++i)
	{
		if (*(l+i)< *(l+i-1))
		{
			*(l+len) = *(l+i);//复制为监视哨,做了点小改动,将监视哨放在最后面
			for (j = i - 1; *(l+len) < *(l+j); --j)
			{
				*(l+j+1) = *(l+j);//记录后移
			}
			*(l+j + 1) = *(l+len);//插入到正确位置
		}
	}
}
int main()
{
	int a[7] = {19,34,24,89,80,10};
	InsertionSort(a,6);
	for (int i = 0; i < 6; ++i)
		printf("%d\n", a[i]);
	return 0;
}

折半插入排序思想:
1.在直接插入排序进行第i个元素时,l[0]到l[i-1]是一个按关键字的有序序列
2.可以利用折半法查找实现在‘l[0]到l[i-1]’中插入l[i]的位置
(1)稳定性
折半插入排序是不稳定的排序方法。
(2)算法效率
a.时间复杂度
最好情况:比较O(n),移动O(1);
最坏情况:比较O(log2n!),移动O(n2);
平均O(n2)
b.空间复杂度
O(1)。

#include<stdio.h>

//折半插入排序
void BiInsertionSort(int l[],int len)
{
	int i, j,low,high,m;
	for (i = 1; i <len; ++i)
	{
		if (*(l+i)< *(l+i-1))
		{
			*(l+len) = *(l+i);//复制为监视哨,做了点小改动,将监视哨放在最后面
			low = 0; high = i - 1;
			while (low<=high)
			{
				m = (low + high)/2;//折半
				if (*(l + len) < *(l + m))
					high = m - 1; 
				else low = m + 1;
			}
			for (j = i - 1;j>high; --j)
			{
				*(l+j+1) = *(l+j);//记录后移
			}
			*(l+high+ 1) = *(l+len);//插入到正确位置
		}
	}
}
int main()
{
	int a[7] = {19,34,24,89,80,10};
	BiInsertionSort(a,6);
	for (int i = 0; i < 6; ++i)
		printf("%d\n", a[i]);
	return 0;
}

希尔排序:将记录序列分成若干子序列,分别对每个子序列进行插入排序,其中d为增量,它的值在排序的过程中从大到小逐渐缩小,直至最后一趟的排序减为1
希尔排序从d+1个位置开始,希尔排序完成增量为d的排序后,序列的特征是:子序列l[i],l[i+d],l[i+2d]是有序的。
当希尔序列的增量为1的排序过程是直接插入排序
(1)稳定性
希尔排序是不稳定的排序方法。
(2)算法效率
(1)时间复杂度
平均O(n1.3)到平均O(n1.5)
(2)空间复杂度
O(1)。

#include<stdio.h>

//希尔排序算法
void ShellInsert(int l[],int len,int d)
{
	int i, j,low,high,m;
	for (i = d; i < len; ++i)
	{
		if (l[i] < l[i - d])
		{
			l[len] = l[i];//监视哨,暂存
			for (j = i - d; j>=0&&(l[j]>l[len]); j=j-d)//注意下标从0开始,所以要改为j>=0
			{
				l[j + d] = l[j];//记录后移,寻找插入点
			}
			l[j+ d] = l[len];//插入
		}
	}
     
}
//增量为d[]的希尔排序
void ShellSort(int l[],int lenl, int lend, int d[])
{
	for (int k = 0; k < lend; ++k)
	{
		//一趟增量为d[k]的插入排序
		ShellInsert(l, lenl, d[k]);
	}
}
int main()
{
	int a[7] = {19,34,24,89,80,10};
	int d[3] = {5,3,1 };
	ShellSort(a,6,3,d);
	for (int i = 0; i < 6; ++i)
		printf("%d\n", a[i]);
	return 0;
}

冒泡排序:
1.从第一个记录开始,两两进行比较,如果l[i]>l[i+1],则两个记录进行交换
2.第1趟比较结果将序列中关键字最大的记录放置到最后一个位置,成为沉底,则最小的则上浮一个位置
(1)稳定性
起泡排序是稳定的排序方法。
(2)时间是复杂性
最好情况:比较O(n), 移动O(1)
最坏情况:比较O(n2), 移动O(n2)
平均情况:O(n2)
(3)空间复杂性
O(1)

#include<stdio.h>

//冒泡排序算法
void BubbleSort(int l[], int len)
{
	int i, j,temp;
	for (i = 0; i <len-1; i++)
	{
		for (j = 0; j <len - i-1; j++)
		{
			if (l[j] > l[j+1])
			{
				temp = l[j];
				l[j] = l[j+1];
				l[j+1] =temp;
			}
		}
	}

}

int main()
{
	int a[6] = {19,34,24,89,80,10 };
	BubbleSort(a, 6);
	for (int i = 0; i < 6; ++i)
		printf("%d\n", a[i]);
	return 0;
}

快速排序:
任取待排序对象序列中的某个对象v,按照对象的关键字大小,将整个序列划分为左右两个子序列:1左侧子序列的关键字都小于等于v的关键字2。右侧子序列中的所有对象的关键字都大于等于v的关键字 3.对象v排在这两个子序列中间。
快速排序一趟后序列有什么特征?
存在一个元素,这个元素左边元素不大于它的关键字,右边元素不小于它的关键字
最好情况的时间复杂度为O(nlog2n)
平均时间复杂度也是O(nlog2n)
由于快速排序是一个递归过程,需一个栈的附加空间,栈的平均深度为O(log2n)。

#include<stdio.h>

//快速排序算法
void Qsort(int l[],int low,int high)
{
	if (low >= high)
		return;
	int temp,ktemp;
	int i = low;
	int j = high;
	temp = l[low];
	while (low < high)
	{
		while (low < high &&  temp<=l[high])
			high--;
		l[low] = l[high];
		while (low < high && temp>=l[low])
		   low++;
		l[high] = l[low];
	}
	l[low] = temp;//枢轴记录到位
	Qsort(l, i, low - 1);
	Qsort(l, low + 1, j);
}

int main()
{
	int a[6] = {19,34,24,89,80,10};
	Qsort(a,0,5);
	for (int i = 0; i < 6; ++i)
		printf("%d\n", a[i]);
	return 0;
}

简单选择排序:1.从n个关键字中选择一个最小值,确定第一个2.第二次再从剩余元素中选择一个最小值,确定第二个
简单选择排序一趟后序列有什么特征?
最小元素排在第一位。
算法概要:1.第一趟排序是在无序区l[0]到l[n-1]中选出关键字最小的记录,然后与l[0]进行交换,确定最小值
2.第二趟排序是在l[1]到l[n-1]之间选关键字最小的记录,将它与a[1]交换,确定次小值
3.第i趟排序是在l[i-1]与l[n-1]中选择关键字最小的记录,将它与l[i-1]进行交换
4.共n-1趟排序
4. 算法分析
(1)稳定性
简单选择排序方法是不稳定的。
(2)时间复杂度
比较O(n2),移动最好O(1),最差O(n)
(3)空间复杂度
为O(1)。

#include<stdio.h>

//简单选择排序算法
void Selectsort(int l[], int len)
{
	int low,temp;
	for (int i = 0; i < len; i++)
	{
		low = i;
		for (int j = i; j < len; j++)
		{
			if (l[j] < l[low])
				low = j;
		}
		if (i != low)
		{
			temp = l[low];
			l[low] = l[i];
			l[i] = temp;
		}
	}
}

int main()
{
	int a[6] = { 19,34,24,89,80,10 };
	Selectsort(a,6);
	for (int i = 0; i < 6; ++i)
		printf("%d\n", a[i]);
	return 0;
}

堆排序属于选择排序:出发点是利用选择排序己经发生的比较,记住比较结果,减少重复比较的次数
大根堆中根节点关键字最大
利用大根堆进行排序,根节点与最后一个节点交换
利用大根堆排序一趟后序列有什么特点?
最大元素在最后。
堆排序算法概要:
1.按关键字建立大根堆
2.输出堆顶元素,采用堆顶元素l[0]与最后一个元素l[n-1]交换,最大元素得到正确的排序位置
3.此时前n-1个元素不满足堆的特性,需重建堆
4.循环执行2,3直到排序完成
筛选算法实例:1.先按照无序序列建立完全二叉树 2.从最后一个非终端结点开始建堆

#include<stdio.h>
void swap(int* a, int* b)
{
	int temp = *b;
	*b = *a;
	*a = temp;
}
//堆排序算法
void HeapAdjust(int l[], int start, int end)
{
	int dad = start;//建立父节点指标和子节点指标
	int son = dad * 2+1;
	while (son <= end)
	{
		if (son + 1 <= end && l[son] < l[son + 1]) //先比较两个子节点,选择最大的
			son++;
		if (l[dad] > l[son])
			return;
		else
		{
			swap(&l[dad], &l[son]);
				dad = son;
			son = dad * 2 + 1;
		}
	}
}
void Heapsort(int l[], int len)
{
	int i;
	for (i = len / 2 - 1; i >= 0; i--)//建立大根堆
		HeapAdjust(l, i, len - 1);
   //先将第一个元素与已排好元素前一位做交换,再重新做调整,直到排序完毕
	for (i = len - 1; i > 0; i--)
	{
		swap(&l[0], &l[i] );
		HeapAdjust(l, 0, i - 1);
	}
	
}
int main()
{
	int a[6] = { 19,34,24,89,80,10 };
	Heapsort(a,6);
	for (int i = 0; i < 6; ++i)
		printf("%d\n", a[i]);
	return 0;
}

归并排序

#include<stdio.h>
void swap(int* a, int* b)
{
	int temp = *b;
	*b = *a;
	*a = temp;
}
void MergeSort(int la[], int lb[],int k, int m,int n)
{
	int i,j;//m是lena-1,n是lenc-1,j是标记b的下标,k是标记a的下标
	for (i = k ,j = m + 1;i <= m &&j <= n;k++)
	{
		if (la[i] < la[j])lb[k] = la[i++];
		else
			lb[k] = la[j++];
	}
	if (i <= m)
		while (k <= n&& i <= m)
			lb[k++] = la[i++];
	if (j <= n)
		while (k <= n&&j<= n)
			lb[k++] = la[j++];
}
int main()
{
	int a[5];
	for (int i = 0; i < 5; i++)
		a[i] = 2 * i +1;
	int b[6];
	for (int i = 0; i < 6; i++)
		b[i] = 2 * (i+1);
	int c[11];
	int lc[11];
	int i;
	for (i = 0; i <5; i++)
		lc[i] = a[i];
	for (i = 0; i <6; i++)
		lc[i + 5] = b[i];
	MergeSort(lc,c,0,4,10);
	for (int i = 0; i < 11; ++i)
		printf("%d\n", c[i]);
	return 0;
}

归并排序一趟后序列有什么特征?
两两有序(二路归并)
归并排序总共需要多少趟?
log2^n
2-路归并排序的思想:
1.将两个记录看成是n个长度为1的有序子表
2.将两两相邻的有序子表进行归并,若子表数为奇数,则留下的一个子表直接进入下一次归并
3.重复2,直到归并成只剩一个长度为n的有序表
归并排序核心算法—有序序列长度为l时的归并
1.l[0]到l[l-1],l[l]到l[2l-1]是有序的
2.l[i]到l[l-1+i],l[l+i]到l[i+2
l-1]是有序的
3.两两归并,Merge(la[],lb[],i,l-1+i,i+2*l-1)

#include<stdio.h>
void swap(int* a, int* b)
{
	int temp = *b;
	*b = *a;
	*a = temp;
}
void Merge(int la[], int lb[], int k, int m, int n)
{
	int i, j;
	for (i = k, j = m + 1; i <= m && j <= n; k++)
	{
		if (la[i] < la[j])lb[k] = la[i++];
		else
			lb[k] = la[j++];
	}
	if(i<=m)
		while (i<=m&&k<=n)
		{
			lb[k++] = la[i++];
		}
	if (j<= n)
		while (j <= n && k <= n)
		{
			lb[k++] = la[j++];
		}
}
void Mergesort(int la[], int lb[], int n, int l)
{
	int i;
	for ( i = 0; 2*l+i-1 <n-1; i = i+l * 2)
	{
		Merge(la, lb, i, l + i - 1, l * 2 + i - 1);
	}
	Merge(la, lb, i, l + i - 1, n-1);
}
void Msort(int la[], int len)
{
	int l = 1;
	int lb[11];
	for (int i = 0; i < 11; ++i)
	{
		lb[i] = la[i];
	}
	while (l < len)
	{
		Mergesort(la, lb, len, l);
		l = l * 2;
		Mergesort(lb, la, len, l);
		l = l * 2;
	}
}
int main()
{
	int a[5];
	for (int i = 0; i < 5; i++)
		a[i] = 2 * i +1;
	int b[6];
	for (int i = 0; i < 6; i++)
		b[i] = 2 * (i+1);
	int c[11];
	int lc[11];
	int i;
	for (i = 0; i <5; i++)
		lc[i] = a[i];
	for (i = 0; i <6; i++)
		lc[i + 5] = b[i];
	Msort(lc,11);
	for (int i = 0; i < 11; ++i)
		printf("%d\n", lc[i]);
	return 0;
}

基数排序的两个主要步骤(操作)是什么?分配和收集
顺序基数排序:
设待排序列A的关键字最大是figure位的整数
1.从最低位,个位开始,扫描关键字的pass位i,等于0的插入Q[0],等于1的插入Q[1]…
2.将Q[0],Q[1],…Q[9]中的数据依次收集到A[]中
3.pass+1直到figure,重复执行1,2两步
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>

void sort(int A[], int n)
{
    int i = 0, j = n, h = 0; int temp;
    while (h < 2)
    {
        while (i < j)//三个元素的快速排序
        {
            while ((i < j) && A[i] == h)
                i++;
            while ((i < j) && A[j] != h)
                j--;
            if (i < j) { temp = A[i]; A[i] = A[j]; A[j] = temp; }
        }
        j = n; h = h + 1;
    }
}
int main()
{
    int a[3] = { 0,2,1 }; 
    sort(a, 2);
    for (int i = 0; i < 3; ++i)
    {
        printf("%d\n", a[i]);
    }
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值