在这一系列, 将阅读和编码算法导论的内容, 参考书籍为第四版的 《Introduction to Algorithms》
将使用 C++ 完成算法的具体实现.
C++ 中 std::vector 容器以及相关操作
#include <iostream>
#include <vector>
int main() {
/** Define number of elements */
int n = 10;
/** Initialize vector nums with values 1 through 10 */
std::vector<int> nums{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
/** Create sub-vector containing the first 3 elements of nums */
std::vector<int> sub(nums.begin(), nums.begin() + 3);
/** Define an empty vector */
std::vector<int> empty{};
/** Output length of sub */
std::cout << "length of sub is " << sub.size() << std::endl;
/** Output elements of sub */
std::cout << "elements of sub are:" << std::endl;
/** Output size of empty vector */
std::cout << "size of empty arr is " << empty.size() << std::endl;
/** Accessing empty[0] would be undefined behavior, so it's commented out */
/** std::cout << "first element of empty arr is " << empty[0] << std::endl; */
/** Loop through and print each element in sub */
for (int i = 0; i < sub.size(); i++) {
std::cout << sub[i] << std::endl;
}
/** Swap the first two elements of nums */
std::swap(nums[0], nums[1]);
/** Append element 11 to the end of nums */
nums.push_back(11);
/** Remove the element at index 3 (fourth element) from nums */
nums.erase(nums.begin() + 3);
/** Modify the last element of nums to 100 */
nums.back() = 100;
/** Print all elements of nums */
std::cout << "elements of nums are:" << std::endl;
for (int i = 0; i < nums.size(); i++) {
std::cout << nums[i] << std::endl;
}
return 0;
}
插入排序
对插入排序伪代码的实现以及调整
本书中的第一个算法即为插入排序, 伪代码见教材 P.19, 按照这个伪代码, 算法的实现如下:
#include <iostream>
#include <vector>
void InsertionSort(std::vector<int> &arr);
void InsertionSort(std::vector<int> &arr) {
for (int i = 1; i < arr.size(); i++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && key < arr[j]) {
/* Move the previous key into the current box and continue to compare */
arr[j + 1] = arr[j];
j -= 1;
}
/* The case key in previous box is smaller than current one */
arr[j + 1] = key;
}
}
int main() {
std::vector<int> nums = {5, 2, 4, 6, 1, 3};
InsertionSort(nums);
std::cout << "array after sort" << ": ";
for (int i = 0; i < nums.size(); i++) {
std::cout << nums[i] << ", ";
}
return 0;
}
上面代码完全按照书中伪代码实现,实际进行微调, 使代码更顺眼, 调整如下
void InsertionSort(std::vector<int> &arr) {
const size_t n = arr.size();
for (size_t i = 1; i < n; ++i) {
int key = arr[i];
size_t j = i; /* track the position of the current key */
while (j > 0 && key < arr[j - 1]) { /** Move arries **/
arr[j] = arr[j - 1];
--j;
}
if (j != i) { /* Check if the array has been moved */
arr[j] = key;
}
}
}
在新的代码中做出了以下几点修改:
- 将
n, i, j, 这些变量从int转换为了无符号整型, 使得能够表示更大的数据(虽然此处只是一个玩具模型). - 在最后增加了一个判断, 只有确实进行过插入排序, 才让
arr[j] = key, 否则当前位置的元素从未移动过, 使用arr[j] = key的操作多余.
2.1 节课后练习选做
2.1-2
Rewrite the INSERTION-SORT procedure to sort into monotonically decreasing in- stead of monotonically increasing order.
即写一个反向的插入排序, 简单修改代码即可
void ReverseInsertionSort(std::vector<int> &arr) {
const size_t n = arr.size();
for (size_t i = 1; i < n; ++i) {
int key = arr[i];
size_t j = i; /* track the position of the current key */
while (j > 0 && key > arr[j - 1]) { /** Move arries **/
arr[j] = arr[j - 1];
--j;
}
if (j != i) { /* Check if the array has been moved */
arr[j] = key;
}
}
}
2.1-4
Consider the searching problem:
Input: A sequence of \(n\) numbers \(\{ a_1, \cdots, a_n\}\) stored in array A[1:n] and a value x.
Output An index i such that x equals A[i] or the special value NIL if x does not appear in A.
尝试自己编写的代码
#include <iostream>
#include <vector>
/** Code of the Searching problem
* in the assignment of 2.1-4 Ch2.1,
* introduction of algorithms
* Input: A sequence of n numbers <a1, ..., an>
* stored in array A[1:n] and a value x
*
* Output: An index i such that x equals A[i]
* or special value NIL if x does not appear in A **/
size_t LinearSearch(std::vector<int> arr, int target);
size_t LinearSearch(std::vector<int> arr, int target) {
const size_t n = arr.size();
for (size_t i = 0; i < n; ++i) {
if (arr[i] == target) {
return i;
}
}
return n;
}
int main() {
std::vector<int> nums = {1, 8, 8, 2, 3, 4};
int target = 2;
size_t res = LinearSearch(nums, target);
(res == nums.size()) ? std::cout << "not found" << std::endl
: std::cout << res << std::endl;
return 0;
}
使用AI查找代码的不足:
- 对于数组,应该传入引用,避免数组的重新拷贝,此外, 针对此例, 应该对数组进行
const修饰, 避免在函数中修改了数组的内容. - 返回值建议使用
std::nullopt, 这类, 但是本文中全部使用C++11标准编写, 因此暂时先不管这个.
修改后的代码如下
size_t LinearSearch(const std::vector<int> &arr, int target) {
const size_t n = arr.size();
for (size_t i = 0; i < n; ++i) {
if (arr[i] == target) {
return i;
}
}
return n;
}
2.1-5
Consider the problem of adding two n-bit binary integers a and b, stored in two \(n\)-element arrays A[0:n-1] and B[0:n-1], where each element is either 0 or 1, \(a = \sum_{i=0}^{n-1} A[i] \cdot 2^i\), and \(b = \sum_{i=0}^{n-1} B[i] \cdot 2^i\). The sum \(c = a + b\) of the two integers should be stored in binary form in an \((n+1)\)-element array C[0:n], where \(c = \sum_{i=0}^n C[i] \cdot 2^i\). Write a procedure ADD-BINARY-INTEGERS that takes as input arrays A and B, along with the length n, and returns array C holding the sum.
这个问题比较简单, 最简单的思路就是将二进制转换为十进制, 做整数的十进制加法, 将结果转换为二进制, 但是这样会有一个问题, 他要求输出的长度比输入的两个数组多一,这样算出来的结果如果没有进位,输出数组可能会和输入数组一样长。
还有一种思路就是直接做二进制计算,这样可以直接制定输出数组的长度。
#include <iostream>
#include <vector>
/** Code of the Add Binary Integers
* in the assignment of 2.1-5 Ch2.1,
* introduction of algorithms
* Input:
* A binary sequence of n numbers <a0, ..., an-1>
* B binary sequence of n numbers <b0, ..., bn-1>
*
* Output:
* C binary sequence of n+1 numbers <c0, ..., cn> **/
/* A naive implementation, change A, B into intger, add to get c, finally change c to binary C */
int Bin2Int(const std::vector<bool> &A);
std::vector<bool> Int2Bin(int a);
std::vector<bool> AddBinaryIntegersNaive(const std::vector<bool> &A, const std::vector<bool> &B);
/* Get the result by adding A and B straightforwardly */
std::vector<bool> AddBinaryIntegers(const std::vector<bool> &A, const std::vector<bool> &B);
int Bin2Int(const std::vector<bool>& A) {
int n = A.size();
int res = 0.0;
for (int i = n - 1; i > -1; --i) {
res += A[i] * (1 << (n - 1 - i));
}
return res;
}
std::vector<bool> Int2Bin(int a) {
std::vector<bool> A;
if (a == 0) {
A.push_back(a);
return A;
}
while (a > 0) {
A.push_back(a & 1);
a >>= 1;
}
std::reverse(A.begin(), A.end()); /** This is stupid, in the future, we will use stack to avoid reverse **/
return A;
}
std::vector<bool> AddBinaryIntegerNaive(const std::vector<bool> &A, const std::vector<bool> &B) {
int a = Bin2Int(A);
int b = Bin2Int(B);
return Int2Bin(a + b);
}
std::vector<bool> AddBinaryInteger(const std::vector<bool> &A, const std::vector<bool> &B) {
int n = A.size();
std::vector<bool> C(n+1, 0); /* Initialize an empty array with size n+1 and all the values are zero */
int carry = 0;
/*
* Current digital = carray + a + b
* Last digital = carray */
for (int i = n - 1; i > -1; --i) {
int a = A[i];
int b = B[i];
int sum = a + b + carry;
C[i+1] = sum & 1;
carry = sum >> 1;
}
C[0] = carry;
return C;
}
int main() {
std::vector<bool> A = {1, 1, 0};
std::vector<bool> B = {1, 1, 0};
// std::vector<bool> C = AddBinaryIntegerNaive(A, B);
std::vector<bool> C = AddBinaryInteger(A, B);
for (int i = 0; i < C.size(); i++) {
std::cout << C[i];
}
/*
std::vector<bool> A = {1, 1, 0};
std::cout << Bin2Int(A) << std::endl;
std::vector<bool> res = Int2Bin(2);
std::cout << "length of res is " << res.size() << std::endl;
std::vector<bool> bin_vec;
A = Int2Bin(6);
for (int i; i < A.size(); i++){
std::cout << A[i];
}
*/
return 0;
}
浙公网安备 33010602011771号