Teaching myself Computer Science - Data Structures: Array

Search for a command to run...

No comments yet. Be the first to comment.
I'm working as a developer for 7 years and found jobs so far without a degree and knowledge of computer science. The companies I aim for next have CS fundamentals as a must-have.
Sometimes the best things happen when you're frustrated over some petty inconvenience. I had one such moment recently by getting frustrated by bad user experience in my bank website. Banks and governm
I set my phone’s language to Tamil a few months ago. There was no big reason behind it. I was typing something on WhatsApp in Tamil and just noticed how the rest of the UI was in English. Felt a sudden rush and changed the language. Tamil is written ...

2025 was an eventful year for me. I know it was a tough year for a lot of people and I had my fair share of losses in the year. Though I’m still processing some of it, overall the year done a lot of good to me. I joined HCL Technologies in March and ...
Last year passed in a jiffy lot of changes happened in life and work. I used to write a yearly review for every year since 2020 but couldn’t write one for 2024. Me and everyone else at home fell sick since new year and took couple of weeks to recover...
I came across this interesting question on HN and decided to write my thoughts on this topic as a blog post to see if my views have changed in the future. The question is there is AI generated SEO content everywhere, and there are platforms that prom...
I'm working as a developer for 7 years. I managed to find jobs so far without a degree and with no knowledge of computer science fundamentals. Now I'm thinking of a job change and the companies I want to work for need strong CS knowledge. There is no way around it. So I'm going to focus on improving my CS knowledge in 2021 and 2022 (if it takes that long).
It is a long shot and I am aware that I might lose motivation and stop. Doing this in Rust, and blogging about my progress is to keep it interesting and to keep doing it as long as possible. Even if I fail, I will gain something and will be better than where I am now.
There are not many resources for implementing data structures and algorithms in Rust. I guess Rust makes it hard to implement any of those because of its safety mechanisms. But personally, Rust is fascinating. It has unique solutions to some of the common problems in other languages. So I decided to go with rust despite some good advice against doing so for this particular use case.
An array is a collection of equal-sized data, stored in a contiguous memory location, and indexed by contiguous integers. The contiguous and equal-sized split are important characteristics. We refer to the memory address of the array's first element and other element's positions can be calculated by simple arithmetic operations.
This makes random access possible, which means we can read from any position of the array without increasing the complexity. Read operation is O(1) regardless of the size of the array. Array also provides constant-time access O(1) when you want to add an element at the end of an array.
Both reading from an array and adding an element at last (push) are constant-time access because calculating the address is just some arithmetic operations. Similarly, removing the last element from an array (pop) is O(1) complexity.
Things get interesting when you want to add or remove an element in any arbitrary position of an array. That's possible but that is O(N) operation. Any operation we want to do in an arbitrary position of an array is complex.
That's enough of theory. Now let's see a bare-bones implementation of an array in rust. The following are the operations that need to be supported for minimal array implementation. This list is not exhaustive.
This is the first time ever I am writing tests in rust and also starting with TDD. It is a good feeling to make a failing test pass.
mod ds_tests {
use super::ds;
#[test]
fn add_elements_to_array() {
let data: Vec<i32> = vec![];
let mut arr = ds::Array::new(0, data);
arr.push(8);
arr.push(18);
assert_eq!(arr.length, 2);
}
#[test]
fn remove_element_from_array() {
let data: Vec<i32> = vec![1, 4, 5];
let mut arr = ds::Array::new(0, data);
arr.pop();
assert_eq!(arr.length, 2);
}
#[test]
fn get_element_at_index() {
let data: Vec<i32> = vec![1,2,5];
let arr = ds::Array::new(0, data);
let value = arr.get_element(1);
assert_eq!(*value, 2);
}
#[test]
fn insert_element_at_index() {
let data: Vec<i32> = vec![1,2,5];
let mut arr = ds::Array::new(0, data);
arr.insert_at(1, 42);
assert_eq!(*arr.get_element(1), 42);
}
#[test]
fn delete_element_at_index() {
let data: Vec<i32> = vec![1,2,5];
let mut arr = ds::Array::new(0, data);
arr.delete_at(1);
assert_ne!(*arr.get_element(1), 2);
}
}
mod ds {
pub struct Array<T> {
pub length: usize,
data: Vec<T>,
}
impl<T: Clone> Array<T> {
pub fn new(length: usize, data: Vec<T>)-> Array<T> {
return Array { length, data};
}
pub fn push(&mut self, elem: T) {
self.data.push(elem);
self.calculate_length();
}
pub fn pop(&mut self) {
self.data.pop();
self.calculate_length();
}
pub fn get_element(&self, index: usize)-> &T {
return &self.data[index];
}
pub fn insert_at(&mut self, index: usize, new_element: T) {
let mut data: Vec<T> = vec![];
for (position, element) in self.data.iter().enumerate() {
if position == index {
data.push(new_element.clone());
}
data.push(element.clone());
}
self.data = data;
self.calculate_length();
}
pub fn delete_at(&mut self, index: usize){
let mut data: Vec<T> = vec![];
for (position, elem) in self.data.iter().enumerate() {
if position != index {
data.push(elem.clone());
}
}
self.data = data;
self.calculate_length();
}
fn calculate_length(&mut self) {
self.length = self.data.len();
}
}
}
Array also provides constant-time access O(1) when you want to add an element at the end of an array.
/u/Nokel81 pointed out that the above statement is incorrect for dynamic arrays without defined capacity. That's because the arrays have to be resized when they're full to accommodate new elements. That's not an O(1) operation. But generally, it is considered as O(1) of amortized cost. More on the amortization in a later blog post, I need to understand the amortized cost analysis methods better before writing it.
Thanks for reading so far. I have no clue how hard or possible it is to implement the above in rust. I'll do some attempts and see where that leads. Please share any feedback, I would really appreciate it. You can consider me a noob in CS fundamentals.