Skip to content

Commit

Permalink
Merge branch 'TheAlgorithms:master' into email-address
Browse files Browse the repository at this point in the history
  • Loading branch information
lyqio committed Sep 19, 2024
2 parents 88d09e3 + b2acfd2 commit 05040a6
Show file tree
Hide file tree
Showing 14 changed files with 626 additions and 201 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ unwrap_used = { level = "allow", priority = 1 }
use_debug = { level = "allow", priority = 1 }
wildcard_enum_match_arm = { level = "allow", priority = 1 }
renamed_function_params = { level = "allow", priority = 1 }
allow_attributes_without_reason = { level = "allow", priority = 1 }
allow_attributes = { level = "allow", priority = 1 }
cfg_not_test = { level = "allow", priority = 1 }
field_scoped_visibility_modifiers = { level = "allow", priority = 1 }
# nursery-lints:
branches_sharing_code = { level = "allow", priority = 1 }
cognitive_complexity = { level = "allow", priority = 1 }
Expand All @@ -163,6 +167,7 @@ suspicious_operation_groupings = { level = "allow", priority = 1 }
use_self = { level = "allow", priority = 1 }
while_float = { level = "allow", priority = 1 }
needless_pass_by_ref_mut = { level = "allow", priority = 1 }
set_contains_or_insert = { level = "allow", priority = 1 }
# cargo-lints:
cargo_common_metadata = { level = "allow", priority = 1 }
# style-lints:
Expand Down
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Bit Manipulation
* [Counting Bits](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/counting_bits.rs)
* [Highest Set Bit](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/highest_set_bit.rs)
* [N Bits Gray Code](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/n_bits_gray_code.rs)
* [Sum Of Two Integers](https://github.com/TheAlgorithms/Rust/blob/master/src/bit_manipulation/sum_of_two_integers.rs)
* Ciphers
* [Aes](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/aes.rs)
Expand Down
58 changes: 33 additions & 25 deletions src/bit_manipulation/counting_bits.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
/*
The counting bits algorithm, also known as the "population count" or "Hamming weight,"
calculates the number of set bits (1s) in the binary representation of an unsigned integer.
It uses a technique known as Brian Kernighan's algorithm, which efficiently clears the least
significant set bit in each iteration.
*/

pub fn count_set_bits(mut n: u32) -> u32 {
//! This module implements a function to count the number of set bits (1s)
//! in the binary representation of an unsigned integer.
//! It uses Brian Kernighan's algorithm, which efficiently clears the least significant
//! set bit in each iteration until all bits are cleared.
//! The algorithm runs in O(k), where k is the number of set bits.

/// Counts the number of set bits in an unsigned integer.
///
/// # Arguments
///
/// * `n` - An unsigned 32-bit integer whose set bits will be counted.
///
/// # Returns
///
/// * `usize` - The number of set bits (1s) in the binary representation of the input number.
pub fn count_set_bits(mut n: usize) -> usize {
// Initialize a variable to keep track of the count of set bits
let mut count = 0;
while n > 0 {
Expand All @@ -24,23 +32,23 @@ pub fn count_set_bits(mut n: u32) -> u32 {
mod tests {
use super::*;

#[test]
fn test_count_set_bits_zero() {
assert_eq!(count_set_bits(0), 0);
}

#[test]
fn test_count_set_bits_one() {
assert_eq!(count_set_bits(1), 1);
macro_rules! test_count_set_bits {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $test_case;
assert_eq!(count_set_bits(input), expected);
}
)*
};
}

#[test]
fn test_count_set_bits_power_of_two() {
assert_eq!(count_set_bits(16), 1); // 16 is 2^4, only one set bit
}

#[test]
fn test_count_set_bits_all_set_bits() {
assert_eq!(count_set_bits(u32::MAX), 32); // Maximum value for u32, all set bits
test_count_set_bits! {
test_count_set_bits_zero: (0, 0),
test_count_set_bits_one: (1, 1),
test_count_set_bits_power_of_two: (16, 1),
test_count_set_bits_all_set_bits: (usize::MAX, std::mem::size_of::<usize>() * 8),
test_count_set_bits_alternating_bits: (0b10101010, 4),
test_count_set_bits_mixed_bits: (0b11011011, 6),
}
}
56 changes: 30 additions & 26 deletions src/bit_manipulation/highest_set_bit.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// Find Highest Set Bit in Rust
// This code provides a function to calculate the position (or index) of the most significant bit set to 1 in a given integer.

// Define a function to find the highest set bit.
pub fn find_highest_set_bit(num: i32) -> Option<i32> {
if num < 0 {
// Input cannot be negative.
panic!("Input cannot be negative");
}

//! This module provides a function to find the position of the most significant bit (MSB)
//! set to 1 in a given positive integer.

/// Finds the position of the highest (most significant) set bit in a positive integer.
///
/// # Arguments
///
/// * `num` - An integer value for which the highest set bit will be determined.
///
/// # Returns
///
/// * Returns `Some(position)` if a set bit exists or `None` if no bit is set.
pub fn find_highest_set_bit(num: usize) -> Option<usize> {
if num == 0 {
return None; // No bit is set, return None.
return None;
}

let mut position = 0;
Expand All @@ -27,22 +30,23 @@ pub fn find_highest_set_bit(num: i32) -> Option<i32> {
mod tests {
use super::*;

#[test]
fn test_positive_number() {
let num = 18;
assert_eq!(find_highest_set_bit(num), Some(4));
}

#[test]
fn test_zero() {
let num = 0;
assert_eq!(find_highest_set_bit(num), None);
macro_rules! test_find_highest_set_bit {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $test_case;
assert_eq!(find_highest_set_bit(input), expected);
}
)*
};
}

#[test]
#[should_panic(expected = "Input cannot be negative")]
fn test_negative_number() {
let num = -12;
find_highest_set_bit(num);
test_find_highest_set_bit! {
test_positive_number: (18, Some(4)),
test_0: (0, None),
test_1: (1, Some(0)),
test_2: (2, Some(1)),
test_3: (3, Some(1)),
}
}
2 changes: 2 additions & 0 deletions src/bit_manipulation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod counting_bits;
mod highest_set_bit;
mod n_bits_gray_code;
mod sum_of_two_integers;

pub use counting_bits::count_set_bits;
pub use highest_set_bit::find_highest_set_bit;
pub use n_bits_gray_code::generate_gray_code;
pub use sum_of_two_integers::add_two_integers;
75 changes: 75 additions & 0 deletions src/bit_manipulation/n_bits_gray_code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/// Custom error type for Gray code generation.
#[derive(Debug, PartialEq)]
pub enum GrayCodeError {
ZeroBitCount,
}

/// Generates an n-bit Gray code sequence using the direct Gray code formula.
///
/// # Arguments
///
/// * `n` - The number of bits for the Gray code.
///
/// # Returns
///
/// A vector of Gray code sequences as strings.
pub fn generate_gray_code(n: usize) -> Result<Vec<String>, GrayCodeError> {
if n == 0 {
return Err(GrayCodeError::ZeroBitCount);
}

let num_codes = 1 << n;
let mut result = Vec::with_capacity(num_codes);

for i in 0..num_codes {
let gray = i ^ (i >> 1);
let gray_code = (0..n)
.rev()
.map(|bit| if gray & (1 << bit) != 0 { '1' } else { '0' })
.collect::<String>();
result.push(gray_code);
}

Ok(result)
}

#[cfg(test)]
mod tests {
use super::*;

macro_rules! gray_code_tests {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $test_case;
assert_eq!(generate_gray_code(input), expected);
}
)*
};
}

gray_code_tests! {
zero_bit_count: (0, Err(GrayCodeError::ZeroBitCount)),
gray_code_1_bit: (1, Ok(vec![
"0".to_string(),
"1".to_string(),
])),
gray_code_2_bit: (2, Ok(vec![
"00".to_string(),
"01".to_string(),
"11".to_string(),
"10".to_string(),
])),
gray_code_3_bit: (3, Ok(vec![
"000".to_string(),
"001".to_string(),
"011".to_string(),
"010".to_string(),
"110".to_string(),
"111".to_string(),
"101".to_string(),
"100".to_string(),
])),
}
}
67 changes: 37 additions & 30 deletions src/bit_manipulation/sum_of_two_integers.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
/**
* This algorithm demonstrates how to add two integers without using the + operator
* but instead relying on bitwise operations, like bitwise XOR and AND, to simulate
* the addition. It leverages bit manipulation to compute the sum efficiently.
*/
//! This module provides a function to add two integers without using the `+` operator.
//! It relies on bitwise operations (XOR and AND) to compute the sum, simulating the addition process.

pub fn add_two_integers(a: i32, b: i32) -> i32 {
let mut a = a;
let mut b = b;
/// Adds two integers using bitwise operations.
///
/// # Arguments
///
/// * `a` - The first integer to be added.
/// * `b` - The second integer to be added.
///
/// # Returns
///
/// * `isize` - The result of adding the two integers.
pub fn add_two_integers(mut a: isize, mut b: isize) -> isize {
let mut carry;
let mut sum;

// Iterate until there is no carry left
while b != 0 {
sum = a ^ b; // XOR operation to find the sum without carry
carry = (a & b) << 1; // AND operation to find the carry, shifted left by 1
let sum = a ^ b;
carry = (a & b) << 1;
a = sum;
b = carry;
}
Expand All @@ -23,26 +26,30 @@ pub fn add_two_integers(a: i32, b: i32) -> i32 {

#[cfg(test)]
mod tests {
use super::add_two_integers;
use super::*;

#[test]
fn test_add_two_integers_positive() {
assert_eq!(add_two_integers(3, 5), 8);
assert_eq!(add_two_integers(100, 200), 300);
assert_eq!(add_two_integers(65535, 1), 65536);
macro_rules! test_add_two_integers {
($($name:ident: $test_case:expr,)*) => {
$(
#[test]
fn $name() {
let (a, b) = $test_case;
assert_eq!(add_two_integers(a, b), a + b);
assert_eq!(add_two_integers(b, a), a + b);
}
)*
};
}

#[test]
fn test_add_two_integers_negative() {
assert_eq!(add_two_integers(-10, 6), -4);
assert_eq!(add_two_integers(-50, -30), -80);
assert_eq!(add_two_integers(-1, -1), -2);
}

#[test]
fn test_add_two_integers_zero() {
assert_eq!(add_two_integers(0, 0), 0);
assert_eq!(add_two_integers(0, 42), 42);
assert_eq!(add_two_integers(0, -42), -42);
test_add_two_integers! {
test_add_two_integers_positive: (3, 5),
test_add_two_integers_large_positive: (100, 200),
test_add_two_integers_edge_positive: (65535, 1),
test_add_two_integers_negative: (-10, 6),
test_add_two_integers_both_negative: (-50, -30),
test_add_two_integers_edge_negative: (-1, -1),
test_add_two_integers_zero: (0, 0),
test_add_two_integers_zero_with_positive: (0, 42),
test_add_two_integers_zero_with_negative: (0, -42),
}
}
Loading

0 comments on commit 05040a6

Please sign in to comment.