数据结构与算法碎片积累

Posted 鸿_H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法碎片积累相关的知识,希望对你有一定的参考价值。

前言:继续肝数据结构与算法课程笔记blog

1、排序算法

1)排序:
假设含有n个记录的序列为r1,r2,…,rn,其相应的关键字分别为k1,k2,…,kn,需确定1,2,…,n的一种排序p1,p2,…,pn,使其相应的关键字满足,kp1<=kp2<=…<=kpn非递减(或非递增)关系,即使序列成为一个按关键字有序的序列rp1,rp2,…,rpn,这样的操作就被称为排序。

2)排序的稳定性
假设ki=kj(1<=i<=n,1<=j<=n,i!=j),且在排序前的序列中ri领先于rj(i<j)
----如果排序后ri仍领先于rj,则称所用的排序方法是稳定的;
----反之,若可能使得排序后的序列中rj领先ri,则称所用的排序算法是不稳定的

【不稳定原因,两者都是731情况下,小甲鱼编号为1,怡静为4,但是排在小甲鱼前面】

3)影响排序算法性能的几个要素:
----时间性能
----辅助空间
----算法的复杂性

2、冒泡排序

1)冒泡排序的基本思想:两两相邻记录的关键字,如果反序则交换,直到没有反序的记录为止

2)冒牌排序的要点:
----两两表示的是相邻的两个元素的意思
----如果有n个元素需要比较n-1次,每一轮减少1次比较
----冒泡排序,因为其从下往上两两比较,所以看上去的就跟泡泡往上冒一样。

3)代码实现:

//210205
#include<stdio.h>

//初始版本
void BubbleSort_first(int k[],int n) 
	int i, j, temp,count1=0,count2=0;
	for (i = 0; i < n - 1; i++) 
		for (j = i + 1; j < n; j++) 
			count1++;
			if (k[i] > k[j]) 
				temp = k[j];
				k[j] = k[i];
				k[i] = temp;
				count2++;
			
		
	
	printf("类似冒泡排序,%d次比较,%d次移动\\n", count1, count2);


//冒泡排序
void BubbleSort(int k[], int n) 
	int i, j, temp,count1=0,count2=0,flag;

	flag = 1;
	for (i = 0; i < n - 1&&flag; i++) 
		for (j = n-1;j >i; j--) 
			count1++;
			flag = 0;
			if (k[j-1] > k[j]) 
				temp = k[j-1];
				k[j-1] = k[j];
				k[j] = temp;
				count2++;
				flag = 1;
			
		
	
	printf("纯正冒泡排序,%d次比较,%d次移动\\n", count1, count2);


int main() 
	int i, a[10] =  5,2,6,0,3,9,1,7,4,8 ;
	//BubbleSort_first(a, 10);
	BubbleSort(a, 10);

	printf("排序后的结果是:");
	for (i = 0; i < 10; i++) 
		printf("%d", a[i]);
	
	printf("\\n\\n");
	return 0;

3、选择排序

1)选择排序算法就是通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换。

2)代码实现

//210205
#include<stdio.h>

void SelectSort(int k[], int n) 
	int i, j, min, temp,count1=0,count2=0;
	for (i = 0; i < n - 1; i++) 
		min = i;
		for (j = i + 1; j < n; j++) 
			if (k[j] < k[min]) 
				min = j;
			
			count1++;
		//找最小的下标

		if (min != i) 
			temp = k[min];
			k[min] = k[i];
			k[i] = temp;
			count2++;
		//如果属于最小,则交换
	
	printf("选择排序,%d次比较,%d次移动\\n", count1, count2);


int main() 
	int i, a[10] =  5,2,6,0,3,9,1,7,4,8 ;
	SelectSort(a, 10);

	printf("排序后的结果是:");
	for (i = 0; i < 10; i++) 
		printf("%d", a[i]);
	
	printf("\\n\\n");
	return 0;

4、直接插入排序

1)直接插入排序算法(straight insertion sort)的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表。

2)代码实现

//210205
#include<stdio.h>

void InsertSort(int k[], int n) 
	int i, j, temp;

	for (i = 1; i < n; i++) 
		if (k[i] < k[i - 1]) 
			temp = k[i];
			for (j = i - 1; k[j] > temp; j--) 
				k[j + 1] = k[j];
			
			k[j + 1] = temp;
		
	


int main() 
	int i, a[10] =  5,2,6,0,3,9,1,7,4,8 ;
	InsertSort(a, 10);

	printf("排序后的结果是:");
	for (i = 0; i < 10; i++) 
		printf("%d", a[i]);
	
	printf("\\n\\n");
	return 0;

5、希尔排序

1)希尔排序是直接插入排序的改进。

2)适用于基本有序、记录数少情况。

3)基本操作,先分为大组交换排序,第二次较小组比较交换排序,循环往复直到两个一组的比较交换情形。

4)代码实现

//210205
#include<stdio.h>

//希尔排序
void InsertSort(int k[], int n) 
	int i, j, temp;
	int gap = n;

	do
	
		gap = gap / 3 + 1;
		for (i = gap; i < n; i++) 
			if (k[i] < k[i - gap]) 
				temp = k[i];
				for (j = i - gap; k[j] > temp; j-=gap) 
					k[j + gap] = k[j];
				
				k[j + gap] = temp;
			
		
	 while (gap>1);


int main() 
	int i, a[10] =  5,2,6,0,3,9,1,7,4,8 ;
	InsertSort(a, 10);

	printf("排序后的结果是:");
	for (i = 0; i < 10; i++) 
		printf("%d", a[i]);
	
	printf("\\n\\n");
	return 0;

6、堆排序

1)堆排序,第一次找第一小,第二次找第二次小,依次类推【现在看这句话有点迷惑211010,是不是大顶堆情况?还是小顶堆情况?还是通用堆排序?】

2)

结点的值都是大于或等于其左右孩子的值,称为大顶堆。小顶堆概念类似,结点的值小于或等于其左右孩子的值,称为小顶堆。

3)要点:
根结点一定是堆中所有结点最大或者最小者,如果按照层序的方式给结点从1开始编号,则结点之间满足如下关系:

3-1)左侧公式,结点比左右孩子都大,表示大顶堆;右侧公式,结点比左右孩子都小,表示小顶堆。

3-2)下标i与2i和2i+1是双亲和子女关系

3-3)把大顶堆和小顶堆用层序遍历存入数组,则一定满足上面的表达式


4)堆排序(heap sort)就是利用堆进行排序的算法,其基本思想是:
----将待排序的序列构造一个大顶堆(或小顶堆)
----此时,整个序列的最大值(最小值)就是堆顶的根结点。将该根结点移走(就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值(最小值))
----然后,将剩余的n-1个序列重新构造一个堆,就会得到n个元素中的最大值(最小值)
----如此反复执行,便能得到一个有序序列

这里的堆遍历,采用的是层序遍历方式。【结合上图中二叉树以及数组来看】

5)代码实现

从下到上采用层序遍历方式,实现堆调整

//210205
#include<stdio.h>
int count=0;

//交换元素
void swap(int k[], int i, int j) 
	int temp;
	temp = k[i];
	k[i] = k[j];
	k[j] = temp;


//调整顶堆,从下往上调整
void HeapAdjust(int k[], int s, int n) 
	int i,temp;

	temp = k[s];//保存的是当前待调整双亲结点
	
	for (i = 2 * s; i <= n; i *= 2) //i =2*s表示的是左孩子;i *= 2表示下一个结点
		count++;
		if (i<n&&k[i] < k[i + 1]) //i<n用于确定不是最后一个结点;k[i]表示左孩子;k[i + 1]表示右孩子
			i++;
		

		if (temp >= k[i]) //如果待调整双亲结点大于或等于孩子,则跳出循环
			break;
		

		k[s] = k[i];//如果待调整双亲结点不大于,则把较大的孩子结点赋值给双亲结点
		s = i;	//双亲待存放的位置保存在s处
		
	

	k[s] = temp;


//堆排序
void HeapSort(int k[], int n) 
	int i;

	//构造大顶堆
	for (i = n / 2; i > 0; i--) 
		HeapAdjust(k, i, n);
	

	for (i = n; i > 1; i--) 
		swap(k, 1, i);
		HeapAdjust(k, 1, i-1);
	


int main() 
	int i, a[10] =  -1,5,2,6,0,3,9,1,7,4 ;
	HeapSort(a, 9);
	printf("%d次比较\\n",count);
	printf("排序后的结果是:");
	for (i = 0; i < 10; i++) 
		printf("%d", a[i]);
	
	printf("\\n\\n");
	return 0;

//调试有问题,老师调试没有-1的,而这里调试打印有-1

7、归并排序

1)归并排序(Merge Sort)就是利用归并的思想实现的排序方法。原理是,假设初始排序有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两合并,得到n/2(上取整)个长度为2或1的有序子序列;再两两归并,…,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。

2)原理图貌似能够理解,但代码实现没理解,需要跟着上面图进行理解。

3)递归实现,不断分为两半,直到分到离散结点为止,然后对离散结点进行排序并合并,返回上一级,直到合并完整。

4)代码实现1(递归方式)

//210205
#include<stdio.h>
#define MAXSIZE 10

//实现归并,并把最后的结果存放到list1里
void merging(int *list1,int list1_size,int *list2,int list2_size) 
	int i, j, k,m;
	int temp[MAXSIZE];

	i = j = k = 0;

	while (i<list1_size&&j<list2_size)
	
		if (list1[i] < list2[j]) 
			temp[k++] = list1[i++];
		
		else
		
			temp[k++] = list2[j++];
		
	
	while (i<list1_size)
	
		temp[k++] = list1[i++];
	
	while (j<list2_size)
	
		temp[k++] = list2[j++];
	

	for (m = 0; m < (list1_size + list2_size); m++) 
		list1[m] = temp[m];
	


//递归方式实现归并排序
void MergeSort(int k[], int n) 
	if (n > 1) 
		int* list1 = k;
		int list1_size = n / 2;
		int* list2 = k + n / 2;
		int list2_size = n - list1_size;

		MergeSort(list1, list1_size);
		MergeSort(list2, list2_size);

		merging(list1, list1_size, list2, list2_size);//合并
	


int main() 
	int i, a[10] =  5,2,6,0,3,9,1,7,4,8 ;
	MergeSort(a, 10);

	printf("排序后的结果是:");
	for (i = 0; i < 10; i++) 
		printf("%d", a[i]);
	
	printf("\\n\\n");
	return 0;

//没懂,应该对照word里面的那个图进行理解这里的迭代方式实现

5)代码实现2(迭代方式)

//210205
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 10

//迭代实现
void MergeSort(int k[], int n) 
	int i, left_min, left_max, right_min, right_max;
	int* temp = (int*)malloc(n * sizeof(int));

	for (i = 1; i < n; i *= 2) 
		for (left_min = 0; left_min < n - i; left_min = right_max) 
			right_min = left_max = left_min + i;
			right_max = left_max + i;

			if (right_max > n) 
				right_max = n;
			

			int next = 0;

			while (left_min<left_max&&right_min<right_max以上是关于数据结构与算法碎片积累的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法碎片积累

数据结构与算法碎片积累

数据结构与算法碎片积累

排序算法积累-----快速排序

内存分配方式及内存碎片

微博推荐算法实践与机器学习平台演进