数据结构与算法碎片积累

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以上是关于数据结构与算法碎片积累的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法碎片积累

数据结构与算法碎片积累

数据结构与算法碎片积累

C++ 代码片段(积累)

带有recyclerviews的碎片需要很长时间才能加载

中继现代碎片容器,道具不自动可用