数据结构与算法回顾之基础排序
2010-12-07 22:29 yearN 阅读(264) 评论(0) 收藏 举报毕业在即,最近对以前学过的数据结构与算法知识再来复习一下。
先来说明一下框架代码:
/// <summary>
/// 基本排序算法
/// </summary>
public class Sort<T>
{
/// <summary>
/// 交换数组中两个成员的位置
/// </summary>
/// <param name="data">排序数组</param>
/// <param name="prev">位置1</param>
/// <param name="next">位置2</param>
private void Swap(T[] data, int prev, int next)
{
T temp = data[prev];
data[prev] = data[next];
data[next] = temp;
}
//…
//…
}
1. 选择排序
原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。
代码:
/// <summary>
/// 选择排序
/// </summary>
/// <param name="data">排序数组</param>
public void SelectionSort(T[] data)
{
if (data == null || data.Length==0)
{
throw new ArgumentNullException("参数引用为空");
}
if (data.Length == 1)
{
return;
}
int least;
for (int i = 0,j; i < data.Length - 1; i++)
{
least = i;
for (j = i + 1; j < data.Length; j++)
{
if ( ((IComparable<T>)data[j]).CompareTo(data[least])<0)
{
least = j;
}
}
if (i != least)
{
Swap(data, least, i);
}
}
}
2. 插入排序
原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。
代码:
/// <summary>
/// 插入排序
/// </summary>
/// <param name="data">排序数组</param>
public void InsertionSort(T[] data)
{
if (data == null || data.Length == 0)
{
throw new ArgumentNullException("参数引用为空");
}
if (data.Length == 1)
{
return;
}
for (int i = 1,j; i < data.Length; i++)
{
IComparable<T> tmp = (IComparable<T>)data[i];
for(j=i;j>0 && tmp.CompareTo(data[j-1])<0;j--)
{
data[j] = data[j - 1];
}
data[j] = (T)tmp;
}
}
3. 冒泡排序
原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。
代码:
/// <summary>
/// 冒泡排序
/// </summary>
/// <param name="data">排序数组</param>
public void BubbleSort(T[] data)
{
if (data == null || data.Length == 0)
{
throw new ArgumentNullException("参数引用为空");
}
if (data.Length == 1)
{
return;
}
for (int i = 0; i < data.Length - 1; i++)
{
for (int j = data.Length - 1; j > i; --j)
{
if (((IComparable<T>)data[j]).CompareTo(data[j - 1]) < 0)
{
Swap(data, j, j - 1);
}
}
}
}
4. 希尔排序
原理:又称增量缩小排序。先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。
代码:
/// <summary>
/// 希尔排序
/// </summary>
/// <param name="data">排序数组</param>
public void ShellSort(T[] data)
{
if (data == null || data.Length == 0)
{
throw new ArgumentNullException("参数引用为空");
}
if (data.Length == 1)
{
return;
}
int i, j, k, h, hCnt;
List<int> list = new List<int>();
//创建增量因子集合
for (h = 1, i = 0; h < data.Length; i++)
{
list.Add(h);
h = 3 * h + i;
}
//增长因子
int[] increments = list.ToArray();
for (i--; i >= 0; i--)
{
h = increments[i];
for (hCnt = h; hCnt < 2 * h; hCnt++)
{
for (j = hCnt; j < data.Length; )
{
IComparable<T> tmp = (IComparable<T>)data[j];
k = j;
while (k - h >= 0 && tmp.CompareTo(data[k - h]) < 0)
{
data[k] = data[k - h];
k -= h;
}
data[k] = (T)tmp;
j += h;
}
}
}
}
5. 快速排序
原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。
代码:
/// <summary>
/// 快速排序
/// </summary>
/// <param name="data">排序数组</param>
public void QuickSort(T[] data)
{
if (data == null || data.Length == 0)
{
throw new ArgumentNullException("参数引用为空");
}
if (data.Length == 1)
{
return;
}
int max = 0;
//找出最大元素放到数组尾部
for (int i = 1; i < data.Length; i++)
{
if (((IComparable<T>)data[max]).CompareTo(data[i]) < 0)
{
max = i;
}
}
Swap(data, data.Length - 1, max);
QuickSort(data, 0, data.Length - 2);
}
private void QuickSort(T[] data, int first, int last)
{
int lower = first + 1;
int upper = last;
Swap(data, first, (first + last) / 2);
IComparable<T> bound = (IComparable<T>)data[first];
while (lower <= upper)
{
while (bound.CompareTo(data[lower]) > 0)
lower++;
while (bound.CompareTo(data[upper]) < 0)
upper--;
if (lower < upper)
Swap(data, lower++, upper--);
else
lower++;
}
Swap(data, upper, first);
if (first < upper - 1)
{
QuickSort(data, first, upper - 1);
}
if (upper + 1 < last)
{
QuickSort(data, upper + 1, last);
}
}
6. 归并排序
原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。
代码:
/// <summary>
/// 归并排序
/// </summary>
/// <param name="data">排序数组</param>
public void MergeSort(T[] data)
{
MergeSort(data, 0, data.Length - 1);
}
private void MergeSort(T[] data, int first, int last)
{
if (first < last)
{
int mid = (first + last) / 2;
MergeSort(data, first, mid);
MergeSort(data, mid + 1, last);
Merge(data, first, mid, last);
}
}
private void Merge(T[] data, int first, int mid, int last)
{
int k = mid - first + 1; //折分左边的长度,为什么要加1呢,因为是从零开始的,不加1长度就不符合.
int m = last - mid; //拆分右边的长度,
T[] left = new T[k];
T[] right = new T[m];
for (int i = 0; i < k; i++)
{
left[i] = data[first + i]; // 把拆分好左边的数放到左数组
}
for (int j = 0; j < m; j++)
{
right[j] = data[mid + j + 1]; //把拆分好右边的数放到右数组
}
int a = 0;
int b = 0;
for (int n = first; n <= last; n++) // for循环,这里n=first,不能改成n=0,因为只有在第一次比较时才等于0,递归后first就不等于0了.
{
if (a < left.Length && b < right.Length)
{
if (((IComparable<T>)left[a]).CompareTo(right[b]) < 0)
{
data[n] = left[a]; //左数组小于右数组,把左数组放入数组arrary
a = a + 1;
}
else
{
data[n] = right[b];//左数组大于右数组,把左数组放入数组arrary
b = b + 1;
}
}
else
{
if (a == left.Length)
{
if (b < right.Length)
{
data[n] = right[b];
b = b + 1;
}
}
if (b == right.Length)
{
if (a < left.Length)
{
data[n] = left[a];
a = a + 1;
}
}
//关于Merge中数组越界的判断,用哨兵法是比较好的,不过对于通用类型来说,我没想到一个好的设置方法,不知哪位大虾给个方案?
}
}
}
7. 基数排序
原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。
代码:
/// <summary>
/// 基数排序
/// </summary>
/// <param name="data">排序数组</param>
/// <param name="bits">多少位数的基数</param>
public void RadixSort(T[] data,int bits)
{
String temp;
int digit, num;
Queue<T>[] digitQueues = new Queue<T>[10];//0,1,2,...9 十个数字,以每个数个为基数的队列
for (int digitVal = 0; digitVal <= 9; digitVal++)
{
digitQueues[digitVal] = new Queue<T>();
}
//sort the list
for (int position = 1; position <= bits; position++)
{
for (int scan = 0; scan < data.Length; scan++)
{
temp = data[scan].ToString();
digit = temp.Substring(bits-position, 1).ToCharArray()[0] - '0';//获取position位的数字码
digitQueues[digit].Enqueue(data[scan]);
}
num = 0;
for (int digitVal = 0; digitVal <= 9; digitVal++)
{
while (digitQueues[digitVal].Count > 0)
{
data[num] = digitQueues[digitVal].Dequeue();
num++;
}
}
}
}
8. 堆排序
原理:利用大根堆或小根堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。
代码:
/// <summary>
/// 堆排序
/// </summary>
/// <param name="data">排序数组</param>
public void HeapSort(T[] data)
{
if (data == null || data.Length == 0)
{
throw new ArgumentNullException("参数引用为空");
}
if (data.Length == 1)
{
return;
}
CreateHeap(data, 0, data.Length);
for (int i = data.Length - 1; i >= 1; --i)
{
T temp = data[0];
data[0] = data[i];
data[i] = temp;
CreateHeap(data, 0, i-1);
}
}
/// <summary>
/// 创建堆
/// </summary>
/// <param name="data">排序数组</param>
/// <param name="root">堆得顶部</param>
/// <param name="index">堆得大小</param>
private void CreateHeap(T[] data,int root, int index)
{
int i; // 循环计数变量
T temp; // 暂存变量
int finish; // 判断堆是否建立完成
i = 2 * root; // 子节点的Index
temp = data[root]; // 暂存Heap的Root 值
finish = 0; // 预设堆建立尚未完成
while (i <= index && finish == 0)
{
if (i < index) // 找最大的子节点
if (((IComparable<T>)data[i]).CompareTo(data[i+1]) < 0)
i++;
if (((IComparable<T>)temp).CompareTo(data[i]) >= 0)
finish = 1; // 堆建立完成
else
{
data[i / 2] = data[i]; // 父节点 = 目前节点
i = 2 * i;
}
}
data[i / 2] = temp; // 父节点 = Root值
}
}
}
最后给出测试代码:
namespace Alg
{
class Program
{
static void Main(string[] args)
{
int[] data = { 23, 123, 23, 12, 3, 2, 56, 67,232,23,23 };
int[] list = { 7843, 4568, 8765, 6543, 7865, 4532, 9987, 3241, 6589, 6622, 1211 };
Sort<int> sort = new Sort<int>();
sort.RadixSort(list,4);
foreach (int element in list)
{
Console.Write(element);
Console.Write(" ");
}
Console.WriteLine();
Console.ReadKey();
}
}
}
浙公网安备 33010602011771号