数据结构与算法分析学习笔记(1)--排序

本文是关于数据结构与算法分析的学习笔记,主要聚焦于排序算法,包括插入排序、希尔排序、堆排序、归并排序和快速排序。插入排序利用已排序部分的特点进行插入;希尔排序通过减小增量的比较来优化排序;堆排序通过维护最大堆的性质实现排序;归并排序采用分治策略;快速排序则以pivot为基础进行划分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

包括插入排序、希尔排序、堆排序、归并排序及快速排序

1、插入排序

插入排序利用了这样的事实:若插入位置为P,则位置0到位置P-1上的元素已排过序。每次插入前P+1个元素的正确位置。

void InsertionSort(ElementType a[], int N)
{
ElementType tmp;
int p, j;
for (p = 1; p < N; p++)
{
tmp = a[p];
for (j = p; j>0 & a[j - 1] > tmp; j--)
a[j] = a[j - 1];
a[j] = tmp;
}
}


2、希尔排序

希尔排序是通过比较相距一段间隔的元素来工作,各趟比较所用的距离随着算法的进行而减少,直到只比较相邻元素的最后一趟排序为止。因此,有时也叫缩小增量排序(diminishing increment sort)。

void shellSort(ElementType a[], int N)
{
ElementType tmp;
int Increment, i, j;
for (Increment = N / 2; Increment > 0; Increment /= 2)
{
for (i = Increment; i < N; i++)
{
tmp = a[i];
for (j = i; j >= Increment; j -= Increment)
{
if (a[j - Increment]>tmp)
a[j] = a[j - Increment];
else
break;
}
a[j] = tmp;
}
}
}


不同增量序列:

(1)Hibbard增量:1,3,7,...,2^k-1

//****************希尔排序(Hibbard增量)****************//

int log2(int n)
{
return int(log(double(n)) / log(double(2)));
}
void shellSort1(ElementType a[], int N)
{
int Kt = log2(N);
int k, Increment, i, j;
ElementType tmp;
for (k = Kt; k > 0; k--)
{
Increment = int(pow(2.0, k) - 1);
for (i = Increment; i < N; i++)
{
tmp = a[i];
for (j = i; j >= Increment; j -= Increment)
{
if (a[j - Increment]>tmp)
a[j] = a[j - Increment];
else
break;
}
a[j] = tmp;
}
}
}


(2)Sedgewick增量:9*4^i-9*2^i+1

//*****************希尔排序(Sedgewick增量)***************//

int log4(int n)
{
return int(log(double(n)) / log(double(4)));
}


void shellSort2(ElementType a[], int N)
{
int Kt = log4((N-1)/9);
int k, Increment, i, j;
ElementType tmp;
for (k = Kt; k >=0; k--)
{
Increment = int(9*pow(4.0, k)-9*pow(2.0,k) + 1);
for (i = Increment; i < N; i++)
{
tmp = a[i];
for (j = i; j >= Increment; j -= Increment)
{
if (a[j - Increment]>tmp)
a[j] = a[j - Increment];
else
break;
}
a[j] = tmp;
}
}
}


3、堆排序

最大堆的父节点大于等于任意一个孩子节点,所以每次可以取出根节点进行排序,为了不使用附加的数组,可以将根节点与最后一个元素交换,然后下滤来保持堆性质,依次类推,最后得到一个从小到大的序列。

#define LeftChild(i) (2*(i)+1)//数组是从0开始的
//***************堆排序********************************//
void PercDown(ElementType a[], int i, int N)
{
int child;
ElementType tmp;
for (tmp = a[i]; LeftChild(i) < N; i = child)
{
child = LeftChild(i);
if (child != N - 1&&a[child+1]>a[child])
child++;
if (tmp < a[child])
a[i] = a[child];
else
break;
}
a[i] = tmp;
}


void Heapsort(ElementType a[], int N)
{
int i;
for (i = N / 2; i >= 0; i--)
PercDown(a, i, N);
for (i = N - 1; i > 0; i--)
{
swap(a[0], a[i]);
PercDown(a, 0, i);
}
}


4、归并排序

对两个已经排好序的子序列排序。

void Merge(ElementType a[], ElementType TmpArray[], int Lpos, int Rpos, int RightEnd)
{
int i, LeftEnd, TmpPos, NumElements;
LeftEnd = Rpos - 1;
TmpPos = Lpos;
NumElements = RightEnd - Lpos + 1;
while (Lpos <= LeftEnd&&Rpos <= RightEnd)
{
if (a[Lpos] <= a[Rpos])
TmpArray[TmpPos++] = a[Lpos++];
else
TmpArray[TmpPos++] = a[Rpos++];
}
while (Lpos <= LeftEnd)
TmpArray[TmpPos++] = a[Lpos++];
while (Rpos <= RightEnd)
TmpArray[TmpPos++] = a[Rpos++];
for (i = 0; i < NumElements; i++, RightEnd--)
{
a[RightEnd] = TmpArray[RightEnd];

}

}


void MSort(ElementType a[], ElementType TmpArray[], int left, int right)
{
int center;
if (left < right)
{
center = (left + right) / 2;
MSort(a, TmpArray, left, center);
MSort(a, TmpArray, center + 1, right);
Merge(a, TmpArray, left, center + 1, right);
}
}


void Mergesort(ElementType a[], int N)
{
ElementType *TmpArray;
TmpArray =(ElementType *)malloc(N*sizeof(ElementType));
if (TmpArray != NULL)
{
MSort(a, TmpArray, 0, N - 1);
free(TmpArray);//free出错,可能是数组越界

}
else
printf("No space for array!!!");
}


5、快速排序

快速排序与归并排序一样也是一种递归的分治方法,选取一个pivot,将小于或等于pivot的放在左边,将大于或等于pivot的放在右边。

//******************快速排序*********************************//
ElementType Median3(ElementType a[], int left, int right)
{
int center = (left + right) / 2;
if (a[left] > a[center])
swap(a[left], a[center]);
if (a[left] > a[right])
swap(a[left], a[right]);
if (a[center] > a[right])
swap(a[center], a[right]);
swap(a[center], a[right - 1]);
return a[right - 1];
}


void Qsort(ElementType a[], int left,int right)
{
int i, j;
ElementType pivot;
if (left + cutoff <= right)
{
pivot = Median3(a, left, right);
i = left;
j = right - 1;
for (;;)
{
while (a[++i] < pivot){}
while (a[--j]>pivot){}
if (i < j)
swap(a[i], a[j]);
else
break;
}
swap(a[i], a[right - 1]);
Qsort(a, left, i - 1);
Qsort(a, i + 1, right);
}
else
{
InsertionSort(a + left, right - left + 1);
}
}


void QuickSirt(ElementType a[], int N)
{
Qsort(a, 0, N - 1);
}


快速查找**************************************//
 void Qselect(ElementType a[], int k, int left, int right)
{
int i, j;
ElementType pivot;
if (left + cutoff <= right)
{
pivot = Median3(a, left, right);
i = left;
j = right - 1;
for (;;)
{
while (a[++i] < pivot){}
while (a[--j]>pivot){}
if (i < j)
swap(a[i], a[j]);
else
break;
}
swap(a[i], a[right - 1]);
if (k <= i)
Qselect(a, k, left, i - 1);
else if (k>i + 1)
Qselect(a, k, i + 1, right);


}
else
{
InsertionSort(a + left, right - left + 1);
}
}
 ElementType QuickSelect(ElementType a[], int k,int N)
 {
Qselect(a, k, 0, N - 1);
return a[k - 1];
 }


用到的其他函数及主函数

#include "stdafx.h"
#include<time.h>
#include<math.h>
#include<stdlib.h>
#include<malloc.h>
#define M 10
#define LeftChild(i) (2*(i)+1)
#define cutoff 3
typedef int ElementType;
void randm(int a[])  //产生随机数
{
int i;
int b;
srand(time(NULL));
for (i = 0; i < M; i++)
{
b = rand();
a[i] =  (b% 100);
}
}
void swap(ElementType &a, ElementType &b)//交换两个数
{
ElementType tmp;
tmp = a;
a = b;
b = tmp;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[M] = { 21,71,71,26,93,95,35,78,84,47 };
//randm(a);


for (int i = 0; i < M; i++)
printf("%d ", a[i]);
printf("\n");
QuickSirt(a, M);
for (int i = 0; i < M; i++)
printf("%d ", a[i]);
ElementType p;
p=QuickSelect(a, 5,10);
printf("\n%d\n", p);


return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值