设一个序列为: a[0], a[1], ..., a[n-1],一个逆序对是指:{ (a[i], a[j]) | a[i] > a[j], i < j }。
统计一个序列中的逆序对个数,可以使用冒泡排序法、二路归并法等。这里介绍利用冒泡排序统计逆序对个数的方法。
核心思想:冒泡排序中,每进行一次交换,则序列的逆序对个数-1。
证明:设冒泡排序过程中 a[i] 与 a[i+1] 进行了一次交换,这说明 a[i] > a[i+1]。序列中逆序对可分为四种:① 非 a[i] 和非 a[i+1] 构成的逆序对;② a[i] 和非 a[i+1] 构成的逆序对;③ a[i+1] 和非 a[i] 构成的逆序对;④ a[i] 和 a[i+1] 构成的逆序对。易知,a[i] 与 a[i+1] 交换时,①、②、③ 类型构成的逆序对个数没变,而类型④的逆序对个数由1变为0,故每进行一次交换序列逆序对个数减少1。
冒泡排序统计逆序对的C++程序:
#include <cstdio> #include <string> #include <functional> using namespace std; /* 对T类型的数组a[lo, hi)进行排序,并返回逆序对个数。 比较由函数对象compare实现,compare(a, b):当 a <= b,返回true。*/ template <class T, class Comp> int countInversionBubble(T * a, int lo, int hi, Comp compare) { int n_inv = 0; // 逆序对个数 while ( lo < hi - 1 ) { int last = lo - 1; // last标示一轮气泡中最后一次交换发生在a[i]与a[i+1]间。 for ( int i = lo; i < hi - 1; ++i ) { if ( !compare(a[i], a[i+1]) ) { T t = a[i+1]; a[i+1] = a[i]; a[i] = t; // 交换a[i]与a[i+1] ++n_inv; last = i; } } hi = last + 1; } return n_inv; } // 测试 int main() { int a1[] = {1}; int n1 = countInversionBubble(a1, 0, 1, less<int>()); // 0 int a2[] = {1, 2, 3}; int n2 = countInversionBubble(a2, 0, 3, less<int>()); // 0 int a3[] = {5, 4, 3, 2, 1}; int n3 = countInversionBubble(a3, 0, 5, less<int>()); // 10 int a4[] = {5, 1, 3, 2, 4}; int n4 = countInversionBubble(a4, 0, 5, less<int>()); // 5 printf("%d %d %d %d\n", n1, n2, n3, n4); return 0; }
原文地址:https://www.cnblogs.com/fyqq0403/p/10503237.html
时间: 2024-11-17 10:07:58