Skip to content

Commit

Permalink
new update
Browse files Browse the repository at this point in the history
  • Loading branch information
ajay-dhangar committed Dec 26, 2024
1 parent b88b654 commit 4bdaa3e
Show file tree
Hide file tree
Showing 101 changed files with 4,749 additions and 1,868 deletions.
80 changes: 80 additions & 0 deletions docs/basic-data-structures/Method Overriding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
id: method-overriding
title: Method Overriding
sidebar_label: Introduction to Method Overriding
sidebar_position: 2
description: 'Method overriding allows a derived class to provide a specific implementation of a method that is already defined in its base class. This feature enables runtime polymorphism in object-oriented programming.'
tags: [dsa, data-structures, Method Overriding]
---

## Method Overriding

### Introduction

Method overriding allows a derived class to provide a specific implementation of a method that is already defined in its base class. This feature enables runtime polymorphism in object-oriented programming, allowing methods to be called on objects of derived classes even when they are referenced by base class pointers or references.

### Syntax

To override a method, you must define a method in the derived class with the same name, return type, and parameter list as the method in the base class.

```cpp
class Base {
public:
virtual ReturnType methodName(ParameterList) {
// Base class implementation
}
};

class Derived : public Base {
public:
ReturnType methodName(ParameterList) override {
// Derived class implementation
}
};
```
### Example
```cpp
#include <iostream>
class Base {
public:
virtual void display() {
std::cout << "Display Base Class" << std::endl;
}
};
class Derived : public Base {
public:
void display() override {
std::cout << "Display Derived Class" << std::endl;
}
};
int main() {
Base* b;
Derived d;
b = &d;
b->display(); // Calls Derived's display
return 0;
}
```
### Key Points About Method Overriding
1. Virtual Functions: The base class method must be declared as virtual to allow overriding. The override keyword in the derived class method is optional but helps clarify intent and catch errors.

2. Polymorphism: Method overriding enables polymorphic behavior, allowing a base class pointer to reference derived class objects and invoke the appropriate overridden method.

3. Access Specifiers: The access level of the overriding method in the derived class must be the same or less restrictive than that of the base class method.

### Rules for Method Overriding

1. Same Signature: The overridden method must have the same name, return type, and parameter list as the base class method.

2. Use of virtual: The base class method must be declared with the virtual keyword to be overridden in the derived class.

3. Return Type Compatibility: The return type of the overriding method can be the same as the base class method or a derived type (covariant return type).

4. Static vs. Dynamic Binding: Overridden methods are resolved at runtime (dynamic binding), while non-overridden methods are resolved at compile time (static binding).

5. Destructors: If a base class has a virtual method, it should also have a virtual destructor to ensure proper cleanup of derived class objects when deleted through a base class pointer.
96 changes: 96 additions & 0 deletions docs/basic-data-structures/Operator Overloading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
id: basic dsa
title: Operator overloading
sidebar_label: Introduction to Operator Overloading
sidebar_position: 2
description: 'Operator overloading allows you to redefine the way operators work for user-defined types (classes and structs). It enables you to specify more intuitive ways to perform operations on objects of your classes.'
tags: [dsa, data-structures, Operator Overloading]
---

## 2 Operator Overloading

### Introduction

Operator overloading allows you to redefine the way operators work for user-defined types (classes and structs). It enables you to specify more intuitive ways to perform operations on objects of your classes.

Overloading an operator does not change:
- the operator precedence,
- the associativity of the operator,
- the arity of the operator, or
- the meaning of how the operator works on objects of
built-in types.

### Syntax
An overloaded operator is implemented as a special member function with the keyword `operator` followed by the symbol of the operator being overloaded.

```cpp
class ClassName {
public:
ReturnType operatorOpSymbol (ParameterList) {
// Function body
}
};
```
### Example
```cpp
class Complex {
public:
double real, imag;
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// Overload the + operator
Complex operator+ (Complex& obj) {
return Complex(real + obj.real, imag + obj.imag);
}
};
```

### Types of Operators that Can Be Overloaded

- Arithmetic operators: `+`, `-`, `*`, `/`, `%`
- Relational operators: `==`, `!=`, `<`, `>`, `<=`, `>=`
- Logical operators: `&&`, `||`, `!`
- Bitwise operators: `&`, `|`, `^`, `~`, `<<`, `>>`
- Increment and decrement operators: `++`, `--`
- Assignment operators: `=`, `+=`, `-=`, `*=`, `/=`, `%=`
- Subscript operator: `[]`
- Function call operator: `()`
- Member access operators: `->`, `.` (only for pointers to members)
- Input and output operators: `>>`, `<<`

Operators that **cannot** be overloaded include: `::`, `.*`, `.`, `? :`, `sizeof`

### Example:
```cpp
#include <iostream>

class Complex {
public:
double real, imag;

Complex(double r = 0, double i = 0) : real(r), imag(i) {}

// Overload the == operator
bool operator== (const Complex& obj) const {
return (real == obj.real && imag == obj.imag);
}
};

int main() {
Complex c1(3.0, 4.0), c2(3.0, 4.0);
if (c1 == c2) {
std::cout << "c1 and c2 are equal" << std::endl;
} else {
std::cout << "c1 and c2 are not equal" << std::endl;
}
return 0;
}
```

### Operator Overloading Rules

When overloading operators, there are several rules to keep in mind:

1. **Preserve the Operator's Original Meaning**: The overloaded operator should make sense in the context of the operation it performs.
2. **Return Types**: The return type should be appropriate for the operation. For example, `operator+` should return a new object, while `operator+=` should return a reference to `*this`.
3. **Symmetry**: Ensure symmetric behavior where applicable. For example, `a == b` should return the same result as `b == a`.
4. **Do Not Overload Operators Irrelevantly**: Only overload operators that make sense for your class. For example, overloading the arithmetic operators for a class that represents a complex number makes sense, but overloading them for a class that represents a database connection does not.
105 changes: 105 additions & 0 deletions docs/basic-data-structures/Strings/Advanced-techniques.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
id: advanced-string
title: "Advanced Strings"
sidebar_label: "Adv Strings"
sidebar_position: 4
description: "StringBuilder is a mutable character sequence in Java that enables efficient modifications of strings without creating new objects, improving performance for dynamic string manipulation."
tags: [String Manipulation, StringBuilder, Java, Mutable Strings, Performance Optimization, Dynamic Text, Programming Concepts]
---

In addition to the basic string methods, several advanced topics and techniques can enhance your string manipulation skills in Java.

## 1. StringBuilder and StringBuffer

### StringBuilder
`StringBuilder` is a mutable sequence of characters. Unlike immutable strings, `StringBuilder` allows you to modify the character sequence without creating new objects.

#### Example:
```java
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb.toString()); // Output: Hello World
StringBuffer
StringBuffer is similar to StringBuilder, but it is synchronized, making it thread-safe. However, this comes at the cost of performance.

Example:
```java

StringBuffer sbf = new StringBuffer("Hello");
sbf.append(" World");
System.out.println(sbf.toString()); // Output: Hello World
```
### 2. Regular Expressions
Java provides a powerful regular expression API through the java.util.regex package. Regular expressions allow you to perform complex string matching and manipulation tasks.

Example:
```java

import java.util.regex.*;

String input = "Hello 123 World";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(input);

while (matcher.find()) {
System.out.println("Found: " + matcher.group()); // Output: Found: 123
}
```
### 3. String Interpolation (Java 15+)
With Java 15, you can use Text Blocks for multi-line string literals. While not exactly string interpolation, it simplifies the creation of multi-line strings.

Example:
```java

String text = """
This is a text block
that spans multiple lines.
""";
System.out.println(text);
```
## 4. Character Encoding
Understanding character encoding (e.g., UTF-8, UTF-16) is crucial for string manipulation, especially when dealing with internationalization or text files.

Example:
```java

byte[] bytes = "Hello".getBytes(StandardCharsets.UTF_8);
String s = new String(bytes, StandardCharsets.UTF_8);
System.out.println(s); // Output: Hello
```
### 5. String Comparison
Understanding string comparison can help you avoid common pitfalls. Use equals() for content comparison and == for reference comparison.

Example:
```java

String s1 = new String("Hello");
String s2 = new String("Hello");

System.out.println(s1 == s2); // Output: false (different objects)
System.out.println(s1.equals(s2)); // Output: true (same content)
```
### 6. Advanced Searching and Sorting
You can implement advanced algorithms for searching (e.g., KMP, Rabin-Karp) and sorting strings based on specific criteria (e.g., alphabetical, length).

Example of Sorting Strings:
```java

String[] arr = {"Banana", "Apple", "Cherry"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // Output: [Apple, Banana, Cherry]
```
### 7. String Manipulation with Streams (Java 8+)
You can use Java Streams to perform complex string manipulations in a functional style.

## Example:
```java

List<String> strings = Arrays.asList("apple", "banana", "cherry");
List<String> uppercased = strings.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(uppercased); // Output: [APPLE, BANANA, CHERRY]
```
## Conclusion
Mastering these advanced string concepts will help you become more proficient in string manipulation in Java. Experiment with these techniques to see how they can enhance your applications.
Loading

0 comments on commit 4bdaa3e

Please sign in to comment.