数据结构与算法回顾之基础排序
2010-12-07 22:29 yearN 阅读(258) 评论(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(); } } }