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