StudyTonight-C-C---中文教程-二-

龙哥盟 / 2024-11-20 / 原文

StudyTonight C/C++ 中文教程(二)

原文:StudyTonight

协议:CC BY-NC-SA 4.0

STL 中的最小和最大操作

原文:https://www.studytonight.com/cpp/stl/stl-min-max-operations

以下是我们将要介绍的功能:

  • 最大方法
  • 最大元素法
  • 最小方法
  • 最小元素法
  • 最小最大值法
  • 最小最大元素法
  • 李氏比较法
  • next _ 置换方法
  • 预排列法

maxmin方法

max方法的语法是:max(object_type a, object_type b, compare_function)

此方法返回 a 和 b 的较大元素。 compare_function 可以省略。如果 max()中没有使用 compare_function,则默认情况下,元素与运算符 > 进行比较。 compare_function 用于确定当对象 a 和对象 b 为非数字类型时,哪个对象更大。

min方法的语法是:min(object_type a, object_type b, compare_function)

此方法返回 a 和 b 的较小元素。 compare_function 可以省略。如果 min()中没有使用 compare_function,则默认情况下,元素与运算符 < 进行比较。 compare_function 用于确定当对象 a 和对象 b 为非数字类型时,哪个对象更小。

下面是一个演示 max()和 min()方法用法的示例。

#include<iostream>
#include<algorithm>

using namespace std;

*/*compare function for strings*/*
bool **myMaxCompare**(string a, string b)
{
    return (a.size() > b.size());
}

bool **myMinCompare**(string a, string b)
{
    return (a.size() > b.size());
}

int main()
{
    int x=4, y=5;

    cout << **max**(x,y);   *// prints 5*
    cout << **min**(x,y);   *// prints 4*

    cout << **max**(2.312, 5.434);     *// prints 5.434*
    cout << **min**(2.312, 5.434);     *// prints 2.312*

    string s = "smaller srting";
    string t = "longer string---";

    string s1 = max(s, t, myMaxCompare);
    cout<< s1 <<endl;  *// prints longer string---*

    string s1 = min(s, t, myMinCompare);
    cout<< s1 <<endl;  *// prints smaller string*
} 

max_elementmin_element方法

max_element 方法的语法是:

max_element(iterator first, iterator last, compare_function)

此方法返回范围[第一个,最后一个]中最大的元素。 compare_function 可以省略。如果 max_element()中没有使用 compare_function,则默认情况下,元素与运算符 > 进行比较。 compare_function 用于确定当对象 a 和对象 b 为非数字类型时,哪个对象更大。

min_element方法的语法是:

min_element(iterator first, iterator last, compare_function)

此方法返回范围[第一个,最后一个]中较小的元素。 compare_function 可以省略。如果 min_element()中没有使用 compare_function,则默认情况下,元素与运算符 < 进行比较。 compare_function 用于确定当对象 a 和对象 b 为非数字类型时,哪个对象更小。

下面是一个演示 max_element()和 min_element()方法用法的示例。

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

bool **myMaxCompare**(int a, int b)
{
    return (a < b);
}

bool **myMinCompare**(int a, int b)
{
    return (a < b);
}

int main()
{
    int values[] = { 1,5,4,9,8,10,6,5,1};
    vector<int> v(values,values+9);

    cout<< ***max_element**(v.begin(), v.end());
    */* prints 10 */*

    cout<< ***min_element**(v.begin(), v.end());
    */* prints 1 */*

    */* using mycompare function */*
    cout<< ***max_element**(v.begin(), v.end(), myMaxCompare);
    */* prints 10 */*

    cout<< ***min_element**(v.begin(), v.end(), myMinCompare);
    */* prints 1 */*
} 

lexicographical_compare方法

此方法的语法是:

**lexicographical_compare**(iterator first1, iterator last1, iterator first2, iterator last2)

它比较范围[第一个 1,最后一个 1]和[第一个 2,最后一个 2],如果第一个范围在字典上小于后一个范围,则返回 true

当我们想要定义如何比较元素时,可以定义和使用自定义比较函数。下面是这个方法的变体的语法。

**lexicographical_compare**(iterator first1, iterator last1, iterator first2, iterator last2, bool compare_function)

下面是演示其用法的程序:

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

bool **myoperator**(char a , char b)
{
    return a > b;

}

int main()
{
    char s[] = "nkvaio";
    char x[] = "xyzabc";
    cout >> **lexicographical_compare**(s, s+6, x, x+6, myoperator);
    */*  prints 0 , Boolean false , since a[4] is not less than b[4]  */*
} 


最小最大值和置换运算

原文:https://www.studytonight.com/cpp/stl/stl-min-max-operations-cont

以下是我们将要介绍的函数,因为我们在上一课中已经介绍了 STL 中最小和最大操作的其他方法。

  • 最小最大值法
  • 最小最大元素法
  • next _ 置换方法
  • 预排列法

minmaxminmax_element方法

minmax 方法的语法是:minmax(object_type a ,object_type b)

该方法返回一对,其中对的第一个元素是 ab 的较小元素,对的第二个元素是 ab 的较大元素。如果 a 和 b 都相等,那么 minmax 返回一对 < a,b > 。minmax 仅在 C++ 11 及以上版本中提供。

下面是一个演示 minmax()方法用法的示例。

#include<iostream>
#include<algorithm>
#include<numeric>

using namespace std;

int main()
{
    pair<int,int> **p**;

    p = **minmax**(2,3);
    */* now p.first = 2 ( smaller element ) 
    And p.second = 3 ( larger element )   */* 

    pair<string,string> **p2**;

    p2 = **minmax**("abcd" , "abce");
    */* p2.first = "abcd" ( lexicographically smaller string )
    And p2.second = "abce" (lexicographically larger string )  */*

    p =  **minmax**(2,2);
    */* p.first = p.second = 2 , */*

    /* minmax can also be used for number of elements */

    p = **minmax**({2,6,5,4,9,8});
    /* now p.first = 2 ( smaller element ) 
    And p.second = 9 ( larger element )   */ 
} 

minmax_element方法的语法是:minmax_element(iterator first, iterator last, compare_function)

此方法返回一对迭代器,其中第一个元素指向范围[第一个,最后一个]中的最小元素,第二个元素指向范围[第一个,最后一个]中的最大元素。

下面是一个演示 minmax_element()用法的示例。

#include<iostream>
#include<algorithm>
#include<array>
using namespace std;

int main ()
{
    array<int,7> **foo** {3,7,2,9,5,8,6};

    auto **result** = **minmax_element**(foo.begin(), foo.end());

    *// print result:*
    cout << "min is " << *result.first;
    cout << "max is " << *result.second;
    return 0;
} 

next_permutationprev_permutation方法

next _ 置换方法的语法是:

next_permutation(iterator first ,iterator last)

此方法在下一个字典式的较大排列中排列范围[第一个,最后一个]中的元素。长度范围 n 内的元素,有 n!(阶乘)元素排列的可能方式,每种排列称为一种排列

prev_permutation方法的语法是:

prev_permutation(iterator first, iterator last)

此方法将范围[第一个,最后一个]中的元素排列在下一个字典式较小的排列中。

下面是一个演示 max_element()和 min_element()方法用法的示例。

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

int main () 
{
    char s[] = "abcd";
    **next_permutation**(s, s+4);
    cout << s >> endl;
    */* prints "abdc" */*

    **rev_permutation**(s, s+4);
    cout << s >> endl;
    */* prints "dcba" */*

    int a[] = {1,2,3,4};

    **next_permutation**(a, a+4);
    */* now a is 1,2,4,3  */*

    vector<int> v(a, a+4);
    */* v is : 1,2,4,3  */*

    **next_permutation**(v.begin(), v.end() );
    */* now v is : 1,3,2,4 */*

    */* resetting a[] for prev_permutation */*
    int a[] = {1,2,3,4};

    **prev_permutation**(a, a+4);
    */* now a is 4,3,2,1  */*

    vector<int> v(a, a+4);
    */* v is : 4,3,2,1  */*
    **prev_permutation**(v.begin(), v.end());
    */* now v is : 4,3,1,2 */*

    return 0;
} 


C++ 程序

基础

C++ 程序:你好世界

原文:https://www.studytonight.com/cpp-programs/cpp-hello-world-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言编写一个基本的 Hello World 程序。

#include<iostream>

using namespace std;

int main()
{
    cout << "Hello World! \n Welcome to Studytonight!!\n\n";
    return 0;
}

输出:

C++ hello world program

现在让我们看看我们在上面的程序中做了什么。

C++ 你好世界程序解释:

为了更好地理解,让我们分解代码的各个部分。

1.#include<iostream>

行首的数字符号(#)指向编译器的预处理程序。
因此,在上述情况下,#include 告诉预处理器包含< iostream >头。

<iostream>头定义了获取输入和输出数据所需的库。

2.using namespace std

这告诉编译器使用标准(std)命名空间,它包括 C++ 标准库的特性。

3.int main()

类似于任何其他编程语言,在 C++ 中,程序的执行从主函数开始:int main()

4.cout声明

cout << "Hello World! \n Welcome to Studytonight!!\n\n"

在 c++ 中,iostream头中定义的流用于输入和输出操作。

cout <<用于向屏幕显示输出。(类似于 C 语言中的printf语句)
cin >>用于从终端获取输入。(类似于 C 语言中的scanf语句)

5.return 0

主方法的返回类型是 int。因此,我们需要返回 0 来终止程序。

保持学习:



C++ 程序:二元加法

原文:https://www.studytonight.com/cpp-programs/cpp-adding-two-numbers-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言编写一个基本程序来加上两个数字

代号:

#include<iostream>

using namespace std;

int main()
{
    //variable declaration
    int a, b;

    //variable declaration and initialization  
    int sum=0;

    //take user input
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to add 2 numbers ===== \n\n";

    cout << "Enter the first Number : ";
    cin >> a;

    cout << "\nEnter the second Number : ";
    cin >> b;

    //Adding the two numbers
    sum = a + b;

    //displaying the final output (sum)
    cout << "\nAddition of the two numbers is : " << sum;

    return 0;
}

输出:

Output for adding 2 numbers

用 C++ 添加 2 个数字的程序解释道:

1。 **int sum=0;**

变量可以在声明时初始化。这通常是为了确保将来要使用的值最初没有设置为某个随机值。

2。sum = a + b;

所有基本的数学运算,如:

  1. 加法(+)T2】

  2. 减法(-)T2】

  3. (/)T2】

  4. 余数或模数(%) 等。

可以在 C++ 中的两个数字之间(一次)执行,类似于任何其他编程语言。

我们会推荐你自己修改程序并测试以上所有操作,培养更好的理解。

保持学习:



C++ 程序:检查数字是正数还是负数

原文:https://www.studytonight.com/cpp-programs/cpp-check-if-the-number-is-positive-or-negative-program

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中确定输入的数字是正数还是负数

这可以通过 C++ 中**if-else**块的概念来实现(学习 C++ if-else )。

下面给出的注释代码将帮助您详细理解这个概念。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Check if the number is positive or negative ===== \n\n";

    int num;

    //taking user input
    cout << "Enter any non-zero Number to be checked: ";
    cin >> num;

    //when the condition inside the if() is true, then it enters the code block
    if (num > 0)
    {
        cout << "\nEntered number is positive";
    }
    else //when if is not executed then it moves to the else block
    {
        cout << "\nEntered number is negative";
    }

    cout << "\n\n\n";

    return 0;
}

输出:

C++ positive or negative

我们希望这篇文章能帮助你更好地理解 C++ 中if else块的逻辑。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:查找字符的 ASCII 值

原文:https://www.studytonight.com/cpp-programs/cpp-find-the-ascii-value-of-the-character-program

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中找到给定字符的 ASCII 值。

程序逻辑:

利用类型铸造的概念可以很容易地做到这一点。

类型转换是指在访问变量时改变变量的数据类型。

示例:如果变量**v**为双精度类型,则可以通过以下代码访问其整数值:

int a = (int) v;

为了更好地理解,请参考下面给出的代码:

代号:

#include <iostream>

using namespace std;

int main()
{
    //variable declaration - a char variable takes a single character as input
    char c;

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Find the ASCII value of a character ===== \n\n";

    //take user input
    cout << "Enter a character : ";
    cin >> c;

    //printing the ASCII value of the entered character
    cout << "\nThe ASCII value of the entered character is : " << (int)c << "\n\n";

    return 0;
}

输出:

C++ ascii

我们希望这篇文章能帮助你更好地理解在 C++ 中确定字符 ASCII 值时寻找类型转换的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



图案

C++ 程序:使用星号(*)打印半金字塔图案

原文:https://www.studytonight.com/cpp-programs/cpp-half-pyramid-pattern-using-star-program

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中使用* 打印半金字塔结构。

使用 ***** 或字母数字的所有此类图案都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有图案将帮助您理解这个概念,并在形成您自己的图案时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print a Half Pyramid using * ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows;

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;
    cout << "\n\nThe required pyramid pattern containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {
        //inner loop is used to decide the number of * in a particular row
        for (j = 1; j <= i; j++)
        {
            cout << "* ";
        }
        cout << endl;
    }

    cout << "\n\n";
    return 0;
}

输出:

C++ half pyramid

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的图案,因为这将帮助您更好地理解嵌套结构。

继续学习:



C++ 程序:使用数字打印半金字塔图案

原文:https://www.studytonight.com/cpp-programs/cpp-half-pyramid-pattern-using-numbers-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言使用数字打印半金字塔结构。

使用 ***** 或字母数字的所有此类图案都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有图案将帮助您理解这个概念,并在形成您自己的图案时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print a Half Pyramid using numbers ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows;

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;
    cout << "\n\nThe required pyramid pattern containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {
        // cout << "Row # " << i << "   ";
        //inner loop is used to decide the number of columns in a particular row
        for (j = 1; j <= i; j++)
        {
            cout << j << " "; //printing the column number within each row
        }

        cout << endl;
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ half pyramid using numbers

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的图案,因为这将帮助您更好地理解嵌套结构。

继续学习:



C++ 程序:使用字符打印半金字塔图案

原文:https://www.studytonight.com/cpp-programs/cpp-half-pyramid-pattern-using-characters-program

大家好!

在本教程中,我们将学习如何使用 C++ 编程语言中的字符打印半金字塔结构。

使用 ***** 或字母数字的所有此类图案都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有图案将帮助您理解这个概念,并在形成您自己的图案时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print a Half Pyramid using Characters ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows;

    //initializing and declaring the character to start each row with
    char c = 'A';

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;
    cout << "\n\nThe required pyramid pattern containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {
        //to display that the outer loop maintains the row number
        cout << "Row # " << i << "   ";

        c = 'A'; //as need to start each row with character 'A'.

        //inner loop is used to decide the number of * in a particular row
        for (j = 1; j <= i; j++)
        {
            cout << c << " "; //printing the column number within each row

            c+=1;// incrementing the ASCII value to move to the next character
        }

        cout << endl;
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ half pyramid using Alphabets

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的图案,因为这将帮助您更好地理解嵌套结构。

继续学习:



C++ 程序:使用星号(*)的反向半金字塔图案

原文:https://www.studytonight.com/cpp-programs/cpp-reverse-half-pyramid-pattern-using-asterix

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中使用* 打印反向半金字塔结构。

使用 ***** 或字母数字的所有此类模式都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有模式将帮助您理解这个概念,并在形成您自己的模式时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print a Reverse Half Pyramid using * ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows;

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;
    cout << "\n\nThe required Reverse Pyramid pattern containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {
        //to display that the outer loop maintains the row number
        cout << "Row # " << i << " contains " << (rows - i + 1) << " stars :  ";

        //inner loop is used to decide the number of * in a particular row
        for (j = rows; j >= i; j--)
        {
            cout << "* ";
        }

        cout << endl;
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ reverse half pyramid using *

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的模式,因为这将帮助您更好地理解嵌套结构。

继续学习:



C++ 程序:使用数字的反向半金字塔图案

原文:https://www.studytonight.com/cpp-programs/cpp-reverse-half-pyramid-pattern-using-numbers

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中使用数字打印反向半金字塔结构。

使用 ***** 或字母数字的所有此类图案都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有图案将帮助您理解这个概念,并在形成您自己的图案时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print a Reverse Half Pyramid using Numbers ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows;

    //to denote the range of numbers in each row
    int last; 

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;
    cout << "\n\nThe required Reverse Pyramid pattern containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {
        //to display that the outer loop maintains the row number
        cout << "Row # " << i << " contains numbers from 1 to " << (rows - i + 1) << " :  ";

        last  = rows -i + 1;
        //inner loop is used to decide the number of * in a particular row
        for (j = 1; j<= last; j++)
        {
            cout << j << " ";
        }

        cout << endl;
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ reverse half pyramid using numbers

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的图案,因为这将帮助您更好地理解嵌套结构。

继续学习:



C++ 程序:使用字符的反向半金字塔图案

原文:https://www.studytonight.com/cpp-programs/cpp-reverse-half-pyramid-pattern-using-characters

大家好!

在本教程中,我们将学习如何使用 C++ 编程语言中的字符打印反向半金字塔结构。

使用 ***** 或字母数字的所有此类图案都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有图案将帮助您理解这个概念,并在形成您自己的图案时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print a Reverse Half Pyramid using Characters ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows, cols;

    //to denote the range of characters in each row
    char c, first,last; 

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;
    cout << "\n\nThe required Reverse Pyramid pattern containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {

        first = 'A';
        last  = first + rows -i ;
        c = 'A';
        cols = rows-i+1;

        //to display that the outer loop maintains the row number
        cout << "Row # " << i << " contains characters from " << first << " to " << last << " :    ";

        //inner loop is used to decide the number of * in a particular row
        for (j = 1; j<= cols; j++)
        {
            cout << c << " ";
            c+=1;
        }

        cout << endl;
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ reverse half pyramid using characters

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的图案,因为这将帮助您更好地理解嵌套结构。

继续学习:



C++ 程序:弗洛伊德三角形程序

原文:https://www.studytonight.com/cpp-programs/cpp-floyds-triangle-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言打印弗洛伊德的三角形

弗洛伊德的三角形是什么?

弗洛伊德的三角形是自然数的直角三角形数组。它是通过用连续数字填充三角形的行来定义的,从左上角的 1 开始:

使用 ***** 或字母数字的所有此类模式都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有模式将帮助您理解这个概念,并在形成您自己的模式时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print a Half Pyramid with Continuous numbers ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows, cols;

    //to denote the range of numbers in each row
    int n=1, first,last; 

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;
    cout << "\n\nThe required Pyramid pattern containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {

        first = n;
        last  = first + i -1;
        cols = i;

        //to display that the outer loop maintains the row number
        //cout << "Row # " << i << " contains the numbers from " << first << " to " << last << " :    ";

        //inner loop is used to decide the number of * in a particular row
        for (j = 1; j<= cols; j++)
        {
            cout << n << " ";
            n+=1;
        }

        cout << endl;
    }

    cout << "\n\n";
    return 0;
}

输出:

C++ half pyramid using continuous numbers

您可以通过删除// 来取消对下面显示的代码行的注释,从而获得每行数字范围的详细信息。

 //cout << "Row # " << i << " contains the numbers from " << first << " to " << last << " :    ";

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的模式,因为这将帮助您更好地理解嵌套结构。

继续学习:



C++ 程序:改进的弗洛伊德三角形

原文:https://www.studytonight.com/cpp-programs/cpp-modified-floyds-triangle-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言打印修改后的弗洛伊德三角形

什么是弗洛伊德三角?

弗洛伊德的三角形是自然数的直角三角形数组。它是通过用连续的数字填充三角形的行来定义的,从左上角的 1 开始。

修改的弗洛伊德三角形中,每行从行号开始,打印所有连续的数字,并包含与行号相等的列数。下面的代码以及输出片段将帮助您理解所提到的定义。

使用 ***** 或字母数字的所有此类模式都是通过使用嵌套循环结构实现的,知道如何迭代以及迭代到哪里。

我们相信,本节涵盖的所有模式将帮助您理解这个概念,并在形成您自己的模式时更好地可视化它,因为这类问题在各种稍加修改的采访中经常被问到。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to print Floyd's Triangle ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, j, rows;

    //to denote the range of numbers in each row
    int n=0, first,last; 

    cout << "Enter the number of rows in the pyramid: ";
    cin >> rows;

    cout << "\n\nThe required Floyd's Triangle containing " << rows << " rows is:\n\n";

    //outer loop is used to move to a particular row
    for (i = 1; i <= rows; i++)
    {

        first = i;
        last  = first + i -1;

        //to display that the outer loop maintains the row number
        //cout << "Row # " << i << " contains the numbers from " << first << " to " << last << " :    ";

        //inner loop is used to decide the number of columns in a particular row
          for (j = 1; j <= i; ++j) // remember: in such cases, ++j works same as j++ (but not always- we will cover this in upcoming posts)
            cout << n + j << " ";

        n++;
        cout << endl; //endl works same as '\n'
    }

    cout << "\n\n";

    return 0;
} 

您可以通过删除// 来取消对下面显示的代码行的注释,从而获得每行数字范围的详细信息。

//cout << "Row # " << i << " contains the numbers from " << first << " to " << last << " :    "; 

输出 1 :当你按原样运行提供的代码时,

C++ Floyd's Triangle 2

输出 2 :当打印出范围的行没有注释时,

C++ Floyd's Triangle 1

我们强烈建议您在开始编程之前先在纸上一行一行地画出这样的模式,因为这将帮助您更好地理解嵌套结构。

继续学习:



数字

C++ 程序:计算用户输入的n个数之和

原文:https://www.studytonight.com/cpp-programs/cpp-find-sum-of-n-numbers-entered-by-the-user

大家好!

在本教程中,我们将学习如何用 C++ 编程语言对用户输入的 n 个数字求和。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the Sum of n numbers entered by the user ===== \n\n";

    //variable declaration
    int n,i,temp;

    //As we are dealing with the sum, so initializing with 0.
    int sum = 0;

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to add : ";
    cin >> n;
    cout << "\n\n";

    //taking n numbers as input from the user and adding them to find the final sum
    for(i=0;i<n;i++)
    {
        cout << "Enter number" << i+1 << " :  ";
        cin >> temp;
        //add each number to the sum of all the previous numbers to find the final sum
        sum += temp;
    }

    cout << "\n\nSum of the " << n << " numbers entered by the user is : "<< sum << endl;
    cout << "\n\n\n";

    return 0;
}

输出:

C++ adding n numbers entered by the user.

现在让我们看看我们在上面的程序中做了什么。

程序解释:

为了更好地理解,让我们分解代码的各个部分。

//taking n numbers as input from the user and adding them to find the final sum
for(i=0; i<n ;i++)
{
    cout << "Enter number" << i+1 << " :  ";
    cin >> temp;

    //add each number to the sum of all the previous numbers to find the final sum
    sum += temp;
}

从这段代码中学到的一件事是,当我们不必使用用户输入的单个元素时,没有必要创建和数组或任何这样的数据结构来存储它们,因为这只会导致空间浪费。

例如,在上面的代码中,由于我们需要找到所有数字的总和,我们将用户输入的每个数字放入同一个变量中,并将其添加到sum变量中,然后再次对下一个数字使用同一个变量,以此类推。

继续学习:



C++ 程序:检查给定的数字是偶数还是奇数

原文:https://www.studytonight.com/cpp-programs/cpp-check-whether-the-given-number-is-even-or-odd

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中检查给定的数字是偶数还是奇数

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the given number is Even or Odd ===== \n\n";

    //variable declaration
    int n;

    //taking input from the command line (user)
    cout << " Enter the number that you want to check : ";
    cin >> n;

    //logic to check if the number is even or odd
    if(n % 2 == 0)
    {
        cout << "\n\nThe entered number "<< n << " is Even\n";
    }
    else
    {
        cout << "\n\nThe entered number "<< n << " is Odd\n";
    }

    cout << "\n\n\n";

    return 0;
}

输出:

C++ even or odd

现在让我们看看我们在上面的程序中做了什么。

程序解释:

为了更好地理解,让我们分解代码的各个部分。

if(n % 2 == 0)
{
    cout << "\n\nThe entered number "<< n << " is Even\n";
}
else
{
    cout << "\n\nThe entered number "<< n << " is Odd\n";
}

代码片段表示确定给定数字是偶数还是奇数的逻辑。

实现这一点的方法有很多,但这里我们想介绍条件语句的逻辑if else以及模数运算(%的使用。

if(condition):

当条件为时,执行这部分代码。如果条件为,那么代码将忽略代码的这一部分,转到下一行。

n%2:这里模数运算返回n除以 2 得到的余数。

根据偶数的定义,一个数除以 2 得到的余数必须是 0 。对于奇数,剩余部分必须是 1

继续学习:



C++ 程序:给定数字的阶乘

原文:https://www.studytonight.com/cpp-programs/cpp-factorial-of-a-given-number-program

大家好!

在本教程中,我们将学习如何使用 C++ 编程语言找到给定数字的阶乘。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the Factorial of a given number ===== \n\n";

    //variable declaration
    int i,n;

    //as we are dealing with the product, it should be initialized with 1.
    int factorial=1;

    //taking input from the command line (user)
    cout << "Enter the number to find the factorial for: ";
    cin >> n;

    //finding the factorial by multiplying all the numbers from 1 to n
    for (i = 1; i <= n; i++)
    {
        factorial *= i; // same as factorial = factorial * i 
    }

    cout << "\n\nThe Factorial of " << n << " is: " << factorial;

    cout << "\n\n\n";

    return 0;
}

输出:

C++ factorial program

现在让我们看看我们在上面的程序中做了什么。

程序解释:

为了更好地理解,让我们分解代码的各个部分。

数学中的阶乘是什么?

数学中正整数 n 的阶乘,用 n 表示!,是所有小于或等于 n 的正整数的乘积:

注:

  1. 阶乘仅针对非负数定义。(> =0)

  2. 0 阶乘的值是 1。( 0!= 1 )

 //as we are dealing with the product, it should be initialized with 1.
    int factorial=1; 

因为阶乘只为非负整数定义,所以它总是产生一个正整数值。此外,由于乘法运算包含在下面给出的逻辑中,因此将其初始化为 1。

1.使用 C++ 寻找阶乘的逻辑:

// finding the factorial by multiplying all the numbers from 1 to n
for (i = 1; i <= n; i++)
{
    factorial *= i; // same as factorial = factorial * i
}

根据上面的定义,我们需要取从 1 开始的所有数字与数字本身的乘积。循环是实现这一点的最佳方式。

factorial *= i;

这与factorial = factorial * i相同,但编码方式更简单。

这适用于所有数学运算,如 **+****-****/****%**

我建议你在自己身上尝试一下,以便更好地理解。

保持学习:



C++ 程序:使用第三个变量交换两个数字

原文:https://www.studytonight.com/cpp-programs/cpp-swap-two-numbers-using-a-3rd-variable

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中使用第三个变量交换两个数字。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Swap two numbers using a 3rd variable ===== \n\n";

    //variable declaration
    int a,b,temp;

    //taking input from the command line (user)
    cout << "Enter the first number : ";
    cin >> a;

    cout << "Enter the second number : ";
    cin >> b;

    cout<<"\n\nValues Before Swapping:  \n"<<endl;
    cout<<"First Number = " << a <<endl;
    cout<<"Second Number = " << b <<endl;

    //Logic for swapping the two numbers using an extra variable 'temp'
    temp = a;
    a = b;
    b = temp;

    cout << "\n\nValues After Swapping:  \n"<<endl;
    cout << "First Number = " << a <<endl;
    cout << "Second Number = " << b <<endl;
    cout << "\n\n\n";

    return 0;
} 

输出:

C++ swapping using a temp variable program

现在让我们看看我们在上面的程序中做了什么。

程序解释:

为了更好地理解,让我们分解代码的各个部分。

//Logic for swapping the two numbers using an extra variable 'temp'
temp = a;
a = b;
b = temp;

这里涉及的逻辑是,与其他编程语言类似,C++ 中的变量存储最近存储到其中的值。

因此,首先我们将a的值放入一个新的变量temp中,这样一旦b的值被赋值给a,那么a的原始值就不会丢失。

然后我们利用temp,将a的原值赋给b

保持学习:



C++ 程序:不使用第三个变量交换两个数字

原文:https://www.studytonight.com/cpp-programs/cpp-swap-two-numbers-without-using-a-3rd-variable

大家好!

在本教程中,我们将学习如何在不使用第三个变量的情况下,用 C++ 编程语言交换两个数字。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Swap two numbers without using a 3rd variable ===== \n\n";

    // variable declaration
    int a,b;

    //taking input from the command line (user)
    cout << "Enter the first number : ";
    cin >> a;

    cout << "Enter the second number : ";
    cin >> b;

    cout << "\n\nValues Before Swapping:  \n"<<endl;
    cout << "First Number = " << a <<endl;
    cout << "Second Number = " << b <<endl;

    // Logic for swapping the two numbers 
    // without using any extra variable
    a = a + b;
    b = a - b;
    a = a - b;

    cout << "\n\nValues After Swapping:  \n"<<endl;

    cout << "First Number = " << a <<endl;
    cout << "Second Number = " << b <<endl;
    cout << "\n\n\n";

    return 0;
} 

输出:

C++ swapping without using a temp variable program

现在让我们看看我们在上面的程序中做了什么。

程序解释:

为了更好地理解,让我们分解代码的各个部分。

//Logic for swapping the two numbers without using any extra variable
a = a + b;
b = a - b;
a = a - b;

这里涉及的逻辑是,与其他编程语言类似,C++ 中的变量存储最近存储到其中的值。

为了理解上面的逻辑,让我们使用一些伪值。

最初,a = 30b=55

然后我们这样做,a = a + b,那么存储在 a 中的新值是:

a = 30 + 55

然后, b = a - b,这里的 a 将是最近存储的值。

所以, b = (30 + 55) - 55 = 30

b = 30(a 的初始值)

最终我们做到了,a = a - b

所以, a = (30 + 55) - 30 = 55

a = 55(b 的初始值)

所以如你所见,我们已经将ab的初始值互换了。

保持学习:



C++ 程序:给定数字的平方根和立方根

原文:https://www.studytonight.com/cpp-programs/cpp-square-root-and-cube-root-of-a-given-number

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中分别利用系统定义的函数 sqrt()cbrt() 找到给定数字的平方根立方根

代号:

#include <iostream>
#include <cmath> // library which has predefined methods sqrt() and cbrt()

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the Square root and Cube root of a given number ===== \n\n";

    // variable declaration
    int n;
    // variable initialization and declaration
    double sq = 1, cb = 1;
    // taking input from the command line (user)
    cout << " \n\nEnter the number you want to find the Square root and Cube root of : ";
    cin >> n;

    // Finding the square root and the cube root using the system defined methods
    sq = sqrt(n);
    cb = cbrt(n);

    cout << " \n\nThe Square Root of the number " << n << " is : " << sq;
    cout << " \n\nThe Cube Root of the number " << n << " is : " << cb;
    cout << "\n\n\n";

    return 0;
} 

输出:

C++ square root and cube root

继续学习:



C++ 程序:查找 GCD 和 LCM

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-find-gcd-and-lcm

大家好!

在本教程中,我们将学习如何用 C++ 编程语言找到给定的两个数字的 GCD 和 LCM。

因此,让我们首先了解这里涉及的术语。

什么是 GCD?

两个数字的最大公约数或 GCD 是将两个数字完美相除的最大可能数(余数 0)。

例:

考虑两个数字是 2 和 3。现在 12 同时以 2 和 3 为因子,但是 6 是同时以 2 和 3 为因子的最小可能数,或者 6 是 2 和 3 的最小倍数。因此 6 是 2 和 3 的 LCM。

什么是 LCM?

两个数字的最小公倍数或 LCM 是两个数字的倍数或以两个数字为因子的最小可能数。

例:

考虑两个数字是 20 和 30。现在 1 完美地将 20 和 30 分开。即使是 2 和 5 也能完美地将 20 和 30 分开。但是 10 是将 20 和 30 除在一起的最大数字,因此被认为是 20 和 30 的 GCD。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the GCD and LCM of two numbers ===== \n\n";

    //variable declaration
    int n1, n2, i;

    //variable declaration and initialization
    int gcd = 1, lcm = 1;  

    //taking input from the command line (user)
    cout << " Enter the two numbers you want to find the GCD and LCM of : \n\n";
    cin >> n1 >> n2;

    //logic to calculate the GCD and LCM of the two numbers
    for ( i = 1; i < 1000; i++)
    {
        //i is the least value that perfectly divides both the numbers and hence the GCD
        if ((n1 % i == 0) && (n2 % i == 0))
        {
            gcd = i;          
        }
    }

    lcm = (n1 * n2) / gcd;

    cout << " \n\nThe GCD of the two numbers : " << n1 << " and " << n2 << " is : " << gcd;
    cout << " \n\nThe LCM of the two numbers : " << n1 << " and " << n2 << " is : " << lcm << "\n\n";
    cout << "\n\n\n";

    return 0;
}

输出:

C++ gcd and lcm program output

继续学习:



C++ 程序:检查数字是不是阿姆斯特朗

原文:https://www.studytonight.com/cpp-programs/cpp-check-whether-the-number-is-armstrong-or-not

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中检查给定的数字是否是阿姆斯特朗

什么是阿姆斯特朗数字?

在数论中,给定基数上的阿姆斯壮数是一个数,它是其各自位数的和,每个位数都是位数的幂。(在编程中,我们通常将其定义为 3 位数)

示例:

153 是阿姆斯壮数字为 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153。(与原编号 153 相同)

但是, 213 不是阿姆斯壮数字因为 2^3 + 1^3 + 3^3 = 8 + 1 + 27 = 36(不等于原来的数字 213)

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to check if the number is Armstrong or not ===== \n\n";

    //variable declaration
    int n, n1, remainder, num = 0;

    //taking input from the command line (user) all at once
    cout << " Enter a positive integer :  ";
    cin >> n;

    //storing the original value before modifying it
    n1=n;

   //Logic to check if it is Armstrong or not for a 3 digit number
    while( n1!=0 )
    {
        remainder = n1 % 10; //storing the digits at the units place
        num += remainder*remainder*remainder;
        n1/=10; 
    }
    cout << "\n\n\n";

    if(num == n)
    {
        cout << n << " is an Armstrong number.";
    }
    else
    {
        cout << n << " is not an Armstrong number.";
    }   
    cout << "\n\n\n";

    return 0;
}

输出:

C++ Armstrong number program output

现在让我们看看我们在上面的程序中做了什么。

程序解释:

为了更好地理解,让我们分解代码的各个部分。

//Logic to check if it is Armstrong or not for a 3 digit number
    while( n1!=0 )
    {
        remainder = n1 % 10; //storing the digits at the units place
        num += remainder*remainder*remainder;
        n1/=10;

    }

以上代码片段用于检查给定的 3 位数是否为阿姆斯特朗

remainder = n1 % 10;

这用于将单位处的数字存储到余数变量中。

num += remainder*remainder*remainder;

这个语句用来执行立方运算,并与前一个和相加,得到给定 3 位数的所有数字的立方的最终和。

n1/=10;

该语句将实际数字除以 10,这样新值就只包含尚未探究的数字。

我们将建议您自行对此进行编程,使用 153 号的笔纸进行逐步分析,以获得更好的理解。

继续学习:



C++ 程序:计算给定数字的位数

原文:https://www.studytonight.com/cpp-programs/cpp-count-number-of-digits-in-a-given-number

大家好!

在本教程中,我们将学习如何使用 c++确定给定数字中的位数。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to count the number of digits in a given number ===== \n\n";

    //variable declaration
    int n, n1, num = 0;

    //taking input from the command line (user)
    cout << " Enter a positive integer :  ";
    cin >> n;

    n1 = n; //storing the original number

    //Logic to count the number of digits in a given number
    while (n != 0)
    {
        n /= 10; //to get the number except the last digit.
        num++; //when divided by 10, updated the count of the digits
    }

    cout << "\n\nThe number of digits in the entered number: " << n1 << " is " << num;
    cout << "\n\n\n";

    return 0;
}

输出:

C++ count number of digits program output

我们希望这篇文章能帮助你更好地理解 C++ 中计算输入数字位数的逻辑。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:确定完全平方

原文:https://www.studytonight.com/cpp-programs/cpp-determine-perfect-square-program

大家好!

在本教程中,我们将演示 C++ 编程语言中判断给定数字是否为完全平方的逻辑。

逻辑:

**sqrt(x)**方法返回x的平方根。

为了更好地理解它的实现,请参考下面给出的评论很好的 CPP 代码。

代号:

#include <iostream>
#include <math.h>

using namespace std;

// Returns true if the given number is a perfect square
bool isPerfectSquare(int n)
{
    // sqrt() method is defined in the math.h library 
    // to return the square root of a given number
    int sr = sqrt(n); 

    if (sr * sr == n)
        return true;
    else
        return false;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to determine if the entered number is perfect square or not ===== \n\n";

    // variable declaration
    int n;
    bool perfect = false;

    // taking input from the command line (user)
    cout << " Enter a positive integer :  ";
    cin >> n;

    // Calling a method that returns true if the 
    // number is a perfect square
    perfect = isPerfectSquare(n);

    if (perfect)
    {
        cout << "\n\nThe entered number " << n << " is a perfect square of the number " << sqrt(n);
    }
    else
    {
        cout << "\n\nThe entered number " << n << " is not a perfect square";
    }

    cout << "\n\n\n";

    return 0;
}

输出:

C++ perfect square program output

让我们看看另一个编号为 81 的数字。

C++ perfect square 2

我们希望这篇文章能帮助你更好地理解在 C++ 中检查完全平方的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:确定数字是质数还是合数

原文:https://www.studytonight.com/cpp-programs/cpp-determine-if-the-number-is-prime-or-composite

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中检查给定的数字是 Prime 还是 Composite

代号:

#include <iostream>
#include <math.h>

using namespace std;

//Returns true if the given number is a Prime number
bool isPrime(int n)
{
    if (n == 1)
        return false; // as 1 is not a prime number

    for (int i = 2; i <= sqrt(n); i++) // Complexity O(SquareRoot(n))
    {
        if (n % i == 0)
            return false;
    }

    return true;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " ===== Most Efficient Program to determine if the entered number is Prime or not. ===== \n\n";

    cout << " ===== Note: 1 is neither Prime nor Composite. ===== \n\n";

    //variable declaration
    int n;
    bool prime = false;

    //taking input from the command line (user)
    cout << " Enter a positive integer other than 1 :  ";
    cin >> n;

    //Calling a method that returns true if the number is Prime
    prime = isPrime(n);

    if (prime)
    {
        cout << "\n\nThe entered number " << n << " is a Prime number.";
    }
    else
    {
        cout << "\n\nThe entered number " << n << " is Composite number.";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ prime or composite number program output

让我们尝试另一种输入,

C++ prime or composite number program output

我们希望这篇文章能帮助你更好地理解如何在 C++ 中检查给定的数字是 Prime 还是 Composite。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:查找输入数字的反转

原文:https://www.studytonight.com/cpp-programs/cpp-find-the-reverse-of-the-entered-number

大家好!

在本教程中,我们将学习如何用 C++ 编程语言找到给定数字的倒数。

找到输入数字的反转的概念可以用来检查回文。

代号:

#include <iostream>
#include <math.h>

using namespace std;

//Returns the reverse of the entered number
int findReverse(int n)
{
    int reverse = 0; //to store the reverse of the given number
    int remainder = 0;

    //logic to compute the reverse of a number
    while (n != 0)
    {
        remainder = n % 10; //store the digit at the units place
        reverse = reverse * 10 + remainder;
        n /= 10;
    }

    return reverse;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " ===== Program to compute the Reverse of the entered number. ===== \n\n";

    //variable declaration
    int n;
    int reverse = 0;

    //taking input from the command line (user)
    cout << " Enter a positive integer to find the reverse of :  ";
    cin >> n;

    //Calling a method that returns the reverse of an entered number
    reverse = findReverse(n);

    cout << "\n\nThe entered number is " << n << " and it's reverse is :" << reverse;

    cout << "\n\n\n";

    return 0;
}

输出:

C++ number reverse program output

我们希望这篇文章能帮助你更好地理解如何在 C++ 中找到给定数字的反转。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:检查给定数字的回文

原文:https://www.studytonight.com/cpp-programs/cpp-palindrome-check-for-a-given-number

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中检查给定的数字是否是回文

要回文的数字的条件:

一个等于其倒数的数。

检查数字是否为回文的步骤:

  1. 计算给定数字的倒数。

  2. 如果数等于它的倒数,它就是回文,否则不是。

代号:

#include <iostream>
#include <math.h>

using namespace std;

//Returns true if the given number is a Palindrome number
bool isPalindrome(int n)
{
    int reverse = 0; //to store the reverse of the given number
    int remainder = 0;

    int n1 = n; //storing the original number for comparing later
    //logic to compute the reverse of a number
    while (n != 0)
    {
        remainder = n % 10;
        reverse = reverse * 10 + remainder;
        n /= 10;
    }

    if (reverse == n1)
        return true;
    else
        return false;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to determine if the entered number is Palindrome or not ===== \n\n";

    //variable declaration
    int n;
    bool palindrome = false;

    //taking input from the command line (user)
    cout << " Enter a positive integer :  ";
    cin >> n;

    //Calling a method that returns true if the number is Palindrome
    palindrome = isPalindrome(n);

    if (palindrome)
    {
        cout << "\n\nThe entered number " << n << " is a Palindrome number.";
    }
    else
    {
        cout << "\n\nThe entered number " << n << " is not a Palindrome number.";
    }

    cout << "\n\n\n";

    return 0;
}

输出:

C++  palindrome program output 1

让我们尝试另一种输入,

C++  palindrome program output 2

我们希望这篇文章能帮助你更好地理解如何在 C++ 中检查给定的数字是不是回文。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



数组

C++ 程序:数组介绍

原文:https://www.studytonight.com/cpp-programs/introduction-to-arrays-in-cpp

大家好!

在本教程中,我们将学习和理解 C++ 编程语言中数组数据结构的基础知识。

C++ 中的数组

在编程中,arrays被引用为结构化的数据类型。数组被定义为存储在连续存储单元中的同质数据的有限有序集合。

为了更好地理解这个概念,我们将推荐您访问:C 语言中的数组,我们已经在这里详细讨论了这个概念。

下面给出的注释代码演示了 C++ 中数组数据结构的基础。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Understand the basics of an Array  ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, n;

    cout << "\n\nEnter the number integers you want in an array: ";
    cin >> n;

    //Declaring an array containing 'n' integers
    int arr[n];

    cout << "\n\n Enter " << n << " integers into an array :\n\n";

    for (i = 0; i < n; i++)
    {
        cin >> arr[i];
    }

    cout << "\n\n The Elements of the Array are: \n\n";

    for (i = 0; i < n; i++)
    {
        cout << " arr [ " << i << " ] = " << arr[i] << endl;
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ Intro to  example

我们希望这篇文章能帮助您更好地理解 CPP 中数组数据结构的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:初始化数组的各种方法

原文:https://www.studytonight.com/cpp-programs/various-ways-of-initializing-an-array-in-cpp

大家好!

在本教程中,我们将学习用 C++ 编程语言初始化数组的各种方法。

要了解 STL 中的数组容器,我们会推荐您访问:https://www.studytonight.com/cpp/stl/stl-container-array,我们已经详细讨论过了。

下面给出的 cpp 编程语言代码借助注释详细解释了其中的每一个。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate various ways to Initialize an Array ===== \n\n";

    // No intitialization only declaration and hence, each of the array element contains a garbage value
    float arr[1000];

    //To initialize an array to all zeros, initialize only the first value to 0\. All 1000 values automatically gets initialized to zero.
    float zeros[1000] = {0.0};

    //If the size is not mentioned, the compiler uses the number of values to be the size of the array
    int no_of_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    // Initial values of pressure(variable) undefined. Only declaration and hence all the elements store a garbage value initially.
    float pressure[10];

    // Only the initial elements contain the characters of the string. Remaining characters gets initialized to zero.
    char website_name[100] = "Studytonight";

    // Array size is 6 (last character is the String end delimeter '\0' ).
    char greeting[] = "Hello";

    return 0;
}

我们希望这篇文章能帮助你更好地理解用 C++ 初始化数组的各种方法。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:如何删除数组元素

原文:https://www.studytonight.com/cpp-programs/cpp-how-to-delete-an-array-element

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中删除特定位置的数组元素。

让我们首先了解删除数组中的元素指的是什么。

删除是指从数组中删除一个元素,而不影响其他元素的顺序。这里的关键任务是确保一旦该元素被删除,其他元素将被相应地移动,以便它们仍然以连续的形式存储,从而遵循数组的属性。

逻辑:

一旦元素被移除,将跟随它的所有元素向前移动 1 个位置。这样,剩余的元素仍将以连续的形式存储。下面的代码将帮助您理解这个逻辑。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate Deletion of an element from an Array ===== \n\n";

    int n;

    cout << " Enter the size of the array: ";
    cin >> n;

    int arr[n], i, pos;

    cout << "\n\n Enter the " << n << " elements of the array: \n\n";
    for(i=0; i<n; i++)
    {
        cin >> arr[i]; 
    }

    //Printing the original array before deletion
    cout << "\n\n The " << n << " elements of the array, before deletion are : \n\n";
    for(i=0; i<n; i++)
    {
        cout << arr[i] << "  "; 
    }

    cout << "\n\n Enter the position, between 1 and " << n << " , of the element to be deleted : ";
    cin >> pos;

    //Performing the deletion logic
    --pos;//as index of the element to be deleted is 1 less than it's position
    for (i = pos; i <= 9; i++)
    {
        arr[i] = arr[i + 1];
    }

    cout << " \n\nThe " << n-1 << " elements of the array, after deletion are : \n\n";
    for(i=0; i<n-1; i++)
    {
        cout << arr[i] << "  "; 
    }

    cout << "\n\n";

    return 0;
} 

输出:

C++ deletion of an array element

我们希望这篇文章能帮助你更好地理解删除 CPP 中数组元素的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:求数组元素的和与均值

原文:https://www.studytonight.com/cpp-programs/find-sum-and-average-of-the-array-elements-in-cpp

大家好!

在本教程中,我们将学习如何用 C++ 编程语言找到数组元素的和与平均值。

C++ 中的数组

在编程中,arrays被称为结构化数据类型。数组被定义为存储在连续存储单元中的同质数据的有限有序集合。

为了更好地理解这个概念,我们建议您访问:https://www.studytonight.com/c/arrays-in-c.php,我们在那里详细讨论了这个概念。

下面给出的注释代码演示了如何在 C++ 中访问数组的元素。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the Sum and Average of the Array elements ===== \n\n";

    //i to iterate the outer loop and j for the inner loop
    int i, n;

    //declaring sum and average as double because average can be a fractional value
    double sum=0, average=0;

    cout << "\n\nEnter the number integers you want in an array: ";
    cin >> n;

    //Declaring an array containing 'n' integers
    int arr[n];

    cout << "\n\n Enter " << n << " integers into an array :\n\n";

    for (i = 0; i < n; i++)
    {
        cout << " Enter arr [ " << i << " ] : ";
        cin >> arr[i];
    }

    cout << "\n\n The Elements of the Array are: \n\n";

    for (i = 0; i < n; i++)
    {
        cout << " arr [ " << i << " ] = " << arr[i] << endl;
        sum += arr[i];
    }

    average = sum/n;

    cout << "\n\n The Sum of the Elements of the Array is : " << sum << "\n\n";

    cout << "\n\n The Average of the Elements of the Array is : " << average << "\n\n";

    cout << "\n\n";

    return 0;
}

输出:

C++ Sum and Average of array elements

我们希望这篇文章能帮助你更好地理解数组的概念,并在 C++ 中访问它的元素。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:访问矩阵元素(2D 数组)

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-access-the-elements-of-a-matrix-2d-array

大家好!

在本教程中,我们将学习如何用 C++ 编程语言访问矩阵(2D 数组)的元素。

在编程中,矩阵只不过是一个 2D 数组。这两个维度被称为

有两种方法可以访问矩阵的元素:

  1. 行主顺序(RMO): 这是访问 2D 数组元素的默认和标准方式。这里我们按行访问元素,即我们首先访问第一行的所有元素,然后只移动到第二行,同样从第一列开始。重复这个过程,直到我们到达矩阵的末尾,即最后一行最后一列的元素。为了更好地理解,请参考下面的代码。

  2. 列主顺序(CMO): 这是访问 2D 数组元素的另一种方式。这里我们按列访问元素,即我们首先访问第一列的所有元素,然后只移动到第二列,同样从第一行开始。重复这个过程,直到我们到达矩阵的末尾,即最后一列最后一行的元素。为了更好地理解,请参考下面的代码。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate accessing the elements of a Matrix ===== \n\n";

    //loop variable r to iterate rows and c to iterate columns.
    int r, c;

    //declaring and initializing the 2D array.
    int arr[5][2] = {{0, 0},
                   {11, 22},
                   {22, 44},
                   {33, 66},
                   {44, 88}};   

    cout << " =====  Accessing the array elements in the Row Major Order ===== \n\n";    
    // outputing the value of each of the array element
    for (r = 0; r < 5; r++)
    {
        for (c = 0; c < 2; c++)
        {
            cout << "arr[" << r << "][" << c << "]: ";
            cout << arr[r][c] << endl;
        }
    }

    cout << "\n\n";

    cout << " =====  Accessing the array elements in the Column Major Order ===== \n\n";    
    // outputing the value of each of the array element
    for (c = 0; c < 2; c++)
    {
        for (r = 0; r < 5; r++)
        {
            cout << "arr[" << r << "][" << c << "]: ";
            cout << arr[r][c] << endl;
        }
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ Access array elements

我们希望这篇文章能帮助你更好地理解访问 2D 数组元素的不同方法。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:相加两个矩阵(2D 数组)

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-add-two-matrices-2d-arrays

大家好!

在本教程中,我们将学习如何用 C++ 编程语言找到两个矩阵的加法(2D 数组)

矩阵加法:

矩阵加法是一种二元运算,通过将两个矩阵的对应元素相加,产生一个矩阵。

约束:对于矩阵加法,有一个必要条件——两个矩阵应该具有相同的维数,即相同的行数和列数。

结果矩阵的维数与两个相加的矩阵的维数相同。

一般来说,积矩阵的元素 a[i][j]是通过将 m1[]i[j]和 m2[i][j] 相加而形成的,即矩阵积的第一个元素是通过将两个矩阵的第一个元素(对应的元素)相加而得到的,第二个元素是通过将两个矩阵的第二个元素相加而形成的,以此类推。

为了更好地理解,请参考下面给出的注释良好的代码。

代号:

#include <iostream>

using namespace std;

int main() {
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate Addition of two Matrices ===== \n\n";

    //loop variable i to iterate rows and j to iterate columns.
    int row, col, i, j;

    //Declaring the 3 matrices (2D arrays) m1-first matrix, m2- second matrix and sum- stores the addition of the two matrices
    int m1[10][10], m2[10][10], sum[10][10];

    cout << "\n\nEnter the number of Rows and Columns of matrix : ";
    cin >> row >> col;

    cout << "\nEnter the " << row * col << " elements of first matrix : \n";

    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            cin >> m1[i][j];
        }
    }

    cout << "\nEnter the " << row * col << " elements of second matrix : \n";

    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            cin >> m2[i][j];
        }
    }

    //calculating the sum matrix
    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            sum[i][j] = m1[i][j] + m2[i][j];
        }
    }

    cout << "\n\nThe first matrix is : \n";

    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            cout << m1[i][j] << "  ";
        }
        cout << endl;
    }

    cout << "\n\nThe second matrix is : \n";

    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            cout << m2[i][j] << "  ";
        }
        cout << endl;
    }

    cout << "\n\nThe Sum matrix is : \n";

    for (i = 0; i < row; i++) {
        for (j = 0; j < col; j++) {
            cout << sum[i][j] << "  ";
        }

        cout << endl;
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ Addition of two matrices

我们希望这篇文章能帮助你更好地理解矩阵加法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:相乘两个矩阵(2D 数组)

原文:https://www.studytonight.com/cpp-programs/cpp-program-multiplication-of-two-matrices-2d-arrays

大家好!

在本教程中,我们将学习如何用 C++ 编程语言找到两个矩阵的乘法(2D 数组)

矩阵乘法:

矩阵乘法是一种二进制运算,通过将两个矩阵相乘产生一个矩阵。

约束:对于矩阵乘法,有一个必要条件:第一个矩阵的列数必须等于第二个矩阵的行数。

结果矩阵具有第一个矩阵的行数和第二个矩阵的列数。

一般来说,积矩阵的一个元素 a[i][j]是由两个数组 m1[i]和 m2[j]的点积构成的,即矩阵积的第一个元素是取第一个矩阵的第一行与第二个矩阵的第一列的点积得到的,矩阵积的第二个元素是取第一个矩阵的第一行与第二个矩阵的第二列的点积得到的,以此类推。

为了更好地理解,请参考下面给出的注释良好的代码。

代号:

#include <iostream>

using namespace std;

int main() {
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate Multiplication of two Matrices ===== \n\n";

    //loop variable i to iterate rows and j to iterate columns.
    int row1, col1, row2, col2, i, j, k;

    //Declaring the 3 matrices (2D arrays) m1-first matrix, m2- second matrix and pro- stores the multiplication of the two matrices
    int m1[10][10], m2[10][10], pro[10][10];

    cout << "\n\nEnter the number of Rows and Columns of first matrix : ";
    cin >> row1 >> col1;

    cout << "\n\nEnter the number of Rows and Columns of second matrix : ";
    cin >> row2 >> col2;

    //Matrix multiplication property
    if (col1 == row2) {
        cout << "\nEnter the " << row1 * col1 << " elements of first matrix : \n";

        for (i = 0; i < row1; i++) {
            for (j = 0; j < col1; j++) {
                cin >> m1[i][j];
            }
        }

        cout << "\nEnter the " << row2 * col2 << " elements of second matrix : \n";

        for (i = 0; i < row2; i++) {
            for (j = 0; j < col2; j++) {
                cin >> m2[i][j];
            }
        }

        // cout << "\n\n"
        //calculating the Product matrix - containing #rows and #columns of the 1st and the 2nd matrix respectively.
        for (i = 0; i < row1; i++) {
            for (j = 0; j < col2; j++) {
                pro[i][j] = 0;

                for (k = 0; k < col1; k++)
                    pro[i][j] = pro[i][j] + (m1[i][k] * m2[k][j]);
            }
        }

        cout << "\n\nThe first matrix is : \n";

        for (i = 0; i < row1; i++) {
            for (j = 0; j < col1; j++) {
                cout << m1[i][j] << "  ";
            }
            cout << endl;
        }

        cout << "\n\nThe second matrix is : \n";

        for (i = 0; i < row2; i++) {
            for (j = 0; j < col2; j++) {
                cout << m2[i][j] << "  ";
            }
            cout << endl;
        }

        cout << "\n\nThe Product matrix is : \n";

        for (i = 0; i < row1; i++) {
            for (j = 0; j < col2; j++) {
                cout << pro[i][j] << "  ";
            }
            cout << endl;
        }

    } else {
        cout << "\n\nMatrix multiplication can't be done as the indices do not match!";
    }

    cout << "\n\n";

    return 0;
}

输出:

C++ Multiplication of two matrices

我们希望这篇文章能帮助你更好地理解矩阵乘法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:寻找数组中最小和最大元素

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-find-the-smallest-and-largest-element-in-an-array

大家好!

在本教程中,我们将学习 C++ 编程语言中的寻找数组中最小和最大的元素

要了解 STL 中的数组容器,我们会推荐您访问:https://www.studytonight.com/cpp/stl/stl-container-array,我们已经详细讨论过了。

下面给出的注释代码将帮助您理解这个概念。

代号:

#include <iostream>
using namespace std;

int findMinimum(int a[], int n)
{
    int mn = a[0]; //initializing minimum

    for (int i = 0; i < n; i++) // complexity O(n)
    {
        mn = min(mn, a[i]); //everytime storing the minimum among the current minimum and the current element
    }
    return mn;
}

int findMaximum(int a[], int n)
{
    int mx = a[0]; //initializing maximum

    for (int i = 0; i < n; i++) // complexity O(n)
    {
        mx = max(mx, a[i]); //everytime storing the maximum among the current maximum and the current element
    }
    return mx;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the Minimum and Maximum element in an Array ===== \n\n";

    int n;

    cout << " Enter the size of the array: ";
    cin >> n;

    int arr[n], i, pos;

    cout << "\n\n Enter the " << n << " elements of the array: \n\n";
    for (i = 0; i < n; i++)
    {
        cin >> arr[i];
    }

    //Printing the original array before deletion
    cout << "\n\n The " << n << " elements of the array are : ";
    for (i = 0; i < n; i++)
    {
        cout << arr[i] << "  ";
    }

    //Calling a method to find the smallest element
    int mn = findMinimum(arr, n);

    //Calling a method to find the largest element
    int mx = findMaximum(arr, n);

    cout << "\n\n\nThe Smallest element in the entered array is: " << mn;

    cout << "\n\nThe Largest element in the entered array is: " << mx << "\n\n\n";

    return 0;
} 

输出:

C++ Min and Max of array

我们希望这篇文章能帮助你更好地理解在 C++ 中寻找数组中最小和最大元素的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:计算子数组最大和

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-compute-maximum-sum-of-the-subarray

大家好!

在本教程中,我们将学习用 C++ 编程语言计算子数组最大和的最有效方法

要了解 STL 中的数组容器,我们会推荐您访问:https://www.studytonight.com/cpp/stl/stl-container-array,我们已经详细讨论过了。

下面给出的 CPP 编程语言代码借助注释详细解释了其中的每一个。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int maxSubArray(int m[], int n)
{

    int sum = 0, s = 0, i;

    for (i = 0; i < n; i++)
    {
        s += m[i];
        if (s < 0)
            s = 0;

        sum = max(s, sum);
    }

    //Sorting the array using the system defined sort() method
    sort(m, m + n);

    //if all the elements are negative then return the largest element of the array
    if (m[n - 1] < 0)
        sum = m[n - 1];

    return sum;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Most Efficient Program to find the Maximum sum of Subarray ===== \n\n";

    int i, n, sum = 0;

    int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4};

    //number of elements in the array
    n = sizeof(arr) / sizeof(arr[0]);

    //Printing the elements of the array
    cout << "\n\n The " << n << " elements of the array are : ";

    for (i = 0; i < n; i++)
    {
        cout << arr[i] << "  ";
    }

    //Calling a method to find the maximum sum of subarray
    sum = maxSubArray(arr, n);

    cout << "\n\n\nThe Maximum sum of the Subarrays of the given array is: " << sum;

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Maximum sum of subarray

我们希望这篇文章能帮助你更好地理解 C++ 中计算数组子数组最大和的逻辑。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



字符串

C++ 程序:将字符串转换为字符数组

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-convert-string-to-array-of-characters

大家好!

在本教程中,我们将学习如何演示如何用 C++ 编程语言将给定的字符串转换成字符数组

逻辑:

这可以通过使用 c_str() 方法来实现。

语法:

 //This is an in-built method defined within the string.h library
    strncpy(cArray, s.c_str(), sizeof(cArray));

为了更好地理解它的用例,请参考下面的代码。

代号:

#include <iostream>

//This header file is used to make use of the strncpy() method
#include <string.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to convert a String to an array of characters  ===== \n\n";

    string s;

    cout << "\n\nEnter a String without any space : ";
    cin >> s;

    cout << "\n\nThe array containing the characters of the strings as it's element is: "
         << "\n\n";

    //The array of characters to be printed
    char cArray[1024];

    //This is an in-built method defined within the string.h library
    strncpy(cArray, s.c_str(), sizeof(cArray));

    //Initializing all the elements of the array to 0, all at once.
    cArray[sizeof(cArray) - 1] = 0;

    //declaring the loop variable within the loop is syntactically correct, but it's scope remains limited to the loop.
    for (int i = 0; cArray[i] != 0; i++)
    {
        cout << "\n cArray[ " << i << " ] :   " << cArray[i];
    }

    cout << "\n\n";

    return 0;
} 

输出:

C++ string to char array

我们希望这篇文章能帮助你更好地理解在 C++ 中将字符串转换成字符数组的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:不使用系统定义方法求字符串长度

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-find-length-of-string-without-using-system-defined-method

大家好!

在本教程中,我们将学习如何演示如何在不使用系统定义方法的情况下,在 C++ 编程语言中找到字符串的长度。

逻辑:

在编程中,字符串的末尾用一个称为字符的特殊分隔符来表示。空字符或字符串终止字符由另一个字符转义序列“\0”表示。

因此,为了计算字符串的长度,我们需要从字符串的第一个字符开始遍历字符串,并不断增加计数器,直到遇到字符,这将告诉我们字符串已经终止。

代号:

#include <iostream>
#include <stdio.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Determine the length of the String without using System defined function, in CPP  ===== \n\n";

    //Variable Declaration
    char s1[100], c = 'a';
    int n = 0, i = 0;

    cout << "\n\nEnter the String you want to find the length for : ";
    cin >> s1;

    //Computing string length without using system defined method
    while (c != '\0')
    {
        c = s1[i];
        i++;
    }

    n = i - 1;

    cout << "\n\nLength of the entered string \"" << s1 << "\" is : " << n << "\n\n\n";

    return 0;
} 

输出:

C++ string length

我们希望这篇文章能帮助你更好地理解在 C++ 中不用系统定义的方法就能找到字符串长度的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:执行字符串连接

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-string-concatenation

大家好!

在本教程中,我们将学习如何用 C++ 编程语言连接用户输入的两个字符串

字符串串联:

在编程中,字符串连接是指将两个字符串组合成一个结果字符串,而不修改每个单独的字符串。

它是通过在两个字符串之间使用“ + ”运算符来执行的。

在串联操作之后,结果字符串的长度是两个单独字符串的总和。

示例:

String1 = 研究

String2 = 今晚

String3 = String1 + String2 = 今晚学习

下面的代码演示了它在 C++ 中的实现。

代号:

#include <iostream>

//This header file is used to make use of the strncpy() method
#include <string.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Concatenate Two Strings in CPP  ===== \n\n";

    //Variable Declaration
    string s1, s2, s3;

    cout << "\n\nEnter the first String without any space : ";
    cin >> s1;

    cout << "\nEnter the second String without any space : ";
    cin >> s2;

    cout << "\n\nThe two individual Strings before Concatenation are :\n\n";
    cout << "String1 = " << s1 << " and its lenght is " << s1.size() << "\n";
    cout << "String2 = " << s2 << " and its lenght is " << s2.size() << "\n\n";

    //Performing Concatenation of two strings using the + operator in CPP
    s3 = s1 + s2;

    cout << "\n\nThe resulting string after the Concatenation of the two strings is :\n\n";
    cout << "String3 = String1 + String2\n";
    cout << "String3 = " << s3 << " and its lenght is " << s3.size() << "\n\n";

    cout << "\nNote: Length of String3 is sum of the individual lengths of both the strings.";

    cout << "\n\n";

    return 0;
} 

输出:

C++ string Concatenation

我们希望这篇文章能帮助你更好地理解 C++ 中字符串连接的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:不使用系统定义方法反转字符串

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-reverse-a-string-without-using-system-defined-method

大家好!

在本教程中,我们将学习如何演示如何在不使用系统定义方法的情况下,在 C++ 编程语言中找到字符串的反转。

查找字符串反向的步骤:

  1. 将要反转的字符串作为输入。

  2. 初始化另一个相同长度的字符数组来存储字符串的反转。

  3. 从头到尾遍历输入字符串,并将每个字符存储在新创建的字符数组中。

代号:

#include <iostream>
#include <stdio.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Reverse the String without using System defined function, in CPP  ===== \n\n";

    //Variable Declaration
    char s1[100], c = 'a';
    int n = 0, i = 0;

    cout << "\n\nEnter the String you want to reverse: ";
    cin >> s1;

    //Computing string length without using system defined method
    while (c != '\0')
    {
        c = s1[i];
        i++;
    }
    n = i - 1;

    cout << "\n\nLength of the entered string \"" << s1 << "\" is : " << n << "\n\n\n";

    //Declaring another char array to store the reverse of the string
    char s2[i];

    i = 0;
    //Logic to store the reverse of a string in another char array
    while (i != n + 1)
    {
        s2[i] = s1[n - i - 1];
        i++;
    }

    cout << "\n\nReverse of the entered string \"" << s1 << "\" is : \"" << s2 << "\"\n\n\n";

    return 0;
} 

输出:

C++ string reverse

我们希望这篇文章能帮助你更好地理解在 C++ 中不用系统定义的方法就能找到字符串的反转的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:检查字符串回文

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-check-string-palindrome

大家好!

在本教程中,我们将学习如何演示如何在 C++ 编程语言中检查字符串是否是回文

字符串成为回文的条件:

如果一个字符串和它的反转相同,那么它就被认为是回文。

检查字符串回文的步骤:

  1. 将要检查回文的字符串作为输入。

  2. 初始化另一个相同长度的字符数组来存储字符串的反转。

  3. 从头到尾遍历输入字符串,并将每个字符存储在新创建的字符数组中。

  4. 如果旧的char数组的每个位置的字符与新的char数组相同,那么这个字符串就是一个回文。否则就不是。

代号:

#include <iostream>
#include <stdio.h>

//This header file is used to make use of the system defined String methods.
#include <string.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Determine whether String is Palindrome or not, in CPP  ===== \n\n";

    //String Variable Declaration
    char s1[100], c = 'a';
    int n1, i = 0;

    cout << "\n\nEnter the String you want to check : ";
    cin >> s1;

    //Computing string length without using system defined method
    while (c != '\0')
    {
        c = s1[i++];
    }

    n1 = i-1;
    char s2[n1+1];

    cout << "Length of the entered string is : " << n1 << "\n\n";

    i = 0;
    //Computing reverse of the String without using system defined method
    while (i != n1 + 1)
    {
        s2[i] = s1[n1 - i - 1];
        i++;
    }

    cout << "Reverse of the entered string is : " << s2 << "\n\n\n";

    i = 0;
    //Logic to check for Palindrome
    while (i != n1)
    {
        if (s2[i] != s1[i])
            break;

        i++;
    }

    if (i != n1)
        cout << "The String \"" << s1 << "\"" << " is not a Palindrome.";
    else
        cout << "The String \"" << s1 << "\"" << " is a Palindrome.";

    cout << "\n\n";

    return 0;
} 

输出:

C++ string palindrome

我们希望这篇文章能帮助你更好地理解如何在 C++ 中检查字符串是否是回文。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



排序

C++ 程序:冒泡排序(标准)

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-bubble-sort-standard

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现标准/未优化的冒泡排序算法

为了从头开始理解冒泡排序算法,我们强烈建议您首先访问我们的教程,因为我们已经介绍了它的逐步实现,这里:https://www.studytonight.com/data-structures/bubble-sort

代号:

#include <iostream>

#include<vector>

using namespace std;

//Global variable declaration so that the variables can be used/accessed within any of the methods
int n;
//Separate method to print the list provided by the calling method
void printElems(vector < int > list) {
    int i;
    for (i = 0; i < n; i++)
        cout << list[i] << "  ";

}

//The Bubble sort logic
void bubbleSort(vector < int > & a) {
    int i, j, k, swap;
    int len = a.size();
    for (int i = len; i > 0; i--) {
        //Any number of variables can be used within the loop provided the syntax is correct.
        for (j = 0, k = 1; k < i; j++, k++) {
            if (a[j] > a[k]) {
                swap = a[j];
                a[j] = a[k];
                a[k] = swap;
            }
        }
        cout << "\n\nThe elements of the list after Pass " << n - i + 1 << " are  : ";
        printElems(a);

    }
}

int main() {
    int i, num;

    //Declaring the Vector to store the integer elements to be sorted
    vector < int > v;

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to implement the Bubble sort algo using Vectors, in CPP  ===== \n\n";

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to sort : ";
    cin >> n;
    cout << "\n\n";

    for (i = 0; i < n; i++) {
        cout << "Enter number" << i + 1 << " :  ";
        cin >> num;
        v.push_back(num);

    }

    cout << "\n\nThe elements of the list before applying the Bubble sort algorithm are : ";

    //Calling the method to print the actual list
    printElems(v);

    //Calling the bubble sort algorithm
    bubbleSort(v);

    cout << "\n\nThe elements of the list after applying the Bubble sort algorithm are  : ";

    //Calling the method to print the sorted list
    printElems(v);

    cout << "\n\n\n";

    return 0;
}

输出 1:

C++ Bubble sort 1

输出 2: 这个场景将向你解释拥有一个优化的冒泡排序算法的必要性,如果列表在两者之间排序,它可以终止程序,而不是一遍又一遍地执行直到结束。

C++ bubble sort 2

在上面的例子中,列表在第一遍之后被排序,但是我们仍然一遍又一遍地应用逻辑直到最后一遍。这个问题由下面讨论的气泡排序算法的优化版本来处理。

为了更好的理解,你可以参考我们这里的一个教程:https://www.studytonight.com/data-structures/bubble-sort

如有任何疑问,欢迎在下方评论区提问!

继续学习:



C++ 程序:冒泡排序(优化)

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-bubble-sort-optimized

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现冒泡排序算法的优化版本。

为了从头开始理解冒泡排序算法,我们强烈建议您首先访问我们的教程,因为我们已经介绍了它的逐步实现,这里:https://www.studytonight.com/data-structures/bubble-sort

代号:

#include <iostream>

#include<vector>

using namespace std;

//Global variable declaration so that the variables can be used/accessed within any of the methods
int n;
//Separate method to print the list provided by the calling method
void printElems(vector < int > list) {
    int i;
    for (i = 0; i < n; i++)
        cout << list[i] << "  ";

}

//The Optimized Bubble sort logic
void bubbleSort(vector < int > & a) {
    int i, j, k, swap, flag;
    int len = a.size();

    for (int i = len; i > 0; i--) {

        //initializing flag to 0 after each pass to check if swapping happens or not in a particular pass
        flag = 0;

        //Any number of variables can be used within the loop provided the syntax is correct.
        for (j = 0, k = 1; k < i; j++, k++) {
            if (a[j] > a[k]) {
                //Swap the elements as they are in opposite order
                swap = a[j];
                a[j] = a[k];
                a[k] = swap;

                // if swapping happens update flag to 1
                flag = 1;
            }

        }

        cout << "\n\nThe elements of the list after Pass " << n - i + 1 << " are  : ";
        printElems(a);

        if (flag == 0) {
            cout << "\n\nTerminating in the " << n - i + 1 << " pass out of " << n << " passes due to the optimized logic\n\n" << endl;
            break;
        }

    }

}

int main() {
    int i, num;

    //Declaring the Vector to store the integer elements to be sorted
    vector < int > v;

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to implement the Optimized Bubble sort algo using Vectors, in CPP  ===== \n\n";

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to sort : ";
    cin >> n;
    cout << "\n\n";

    for (i = 0; i < n; i++) {
        cout << "Enter number" << i + 1 << " :  ";
        cin >> num;
        v.push_back(num);

    }

    cout << "\n\nThe elements of the list before applying the Optimized Bubble sort algorithm are : ";

    //Calling the method to print the actual list
    printElems(v);

    //Calling the bubble sort algorithm
    bubbleSort(v);

    cout << "\n\nThe elements of the list after applying the Optimized Bubble sort algorithm are  : ";

    //Calling the method to print the sorted list
    printElems(v);

    cout << "\n\n\n";

    return 0;
}

输出 1: 这个场景将向你解释拥有一个优化的冒泡排序算法的必要性,如果列表在两者之间排序,它可以终止程序,而不是一遍又一遍地执行直到结束。

C++ optimized bubble sort 2

在上面的例子中,列表在第一遍之后被排序,所以在第二遍中,没有交换,因此我们的优化算法理解列表已经被排序,并在这一遍中终止程序,而不是让它执行到最后一遍。

为了更好的理解,你可以参考我们这里的一个教程:https://www.studytonight.com/data-structures/bubble-sort

如有任何疑问,欢迎在下方评论区提问!

继续学习:



C++ 程序:选择排序

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-selection-sort

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现选择排序算法

为了从头开始理解选择排序算法,我们强烈建议您首先在同一天访问我们的教程,因为我们已经介绍了它的逐步实现,这里:https://www . study south . com/data-structures/Selection-sorting

代号:

#include <iostream>

#include<vector>

using namespace std;

//Separate method to print the list provided by the calling method
void printElems(vector < int > list) {
    int i;
    int len = list.size();
    for (i = 0; i < len; i++)
        cout << list[i] << "  ";

}

//The Selection sort logic
void selectionSort(vector < int > & a) {
    int i, min, k, swap, location;
    int len = a.size();

    for (i = 0; i < len - 1; i++) {
        min = a[i];
        location = i;

        for (k = i + 1; k < len; k++) {
            if (min > a[k]) {
                min = a[k];
                location = k;
            }
        }

        //Putting the minimum value of each pass to its correct location
        swap = a[i];
        a[i] = a[location];
        a[location] = swap;

        cout << "\n\nThe elements of the list after Pass " << i + 1 << " are  : ";
        printElems(a);

    }

}

int main() {
    int i, num, n;

    //Declaring the Vector to store the integer elements to be sorted
    vector < int > v;

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to implement the Selection Sort algo using Vectors, in CPP  ===== \n\n";

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to sort : ";
    cin >> n;
    cout << "\n\n";

    for (i = 0; i < n; i++) {
        cout << "Enter number" << i + 1 << " :  ";
        cin >> num;
        v.push_back(num);

    }

    cout << "\n\nThe elements of the list before applying the Selection sort algorithm are : ";

    //Calling the method to print the actual list
    printElems(v);

    //Calling the bubble sort algorithm
    selectionSort(v);

    cout << "\n\nThe elements of the list after applying the Selection sort algorithm are  : ";

    //Calling the method to print the sorted list
    printElems(v);

    cout << "\n\n\n";

    return 0;
}

输出:

C++ Selection sort

如有任何疑问,欢迎在下方评论区提问!

继续学习:



C++ 程序:插入排序

原文:https://www.studytonight.com/cpp-programs/cpp-programs-for-insertion-sort

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现插入排序算法

为了从头开始理解插入排序算法,我们强烈建议您首先访问我们的教程,因为我们已经介绍了它的逐步实现,这里:https://www . study now . com/data-structures/insert-sorting

代号:

#include <iostream>

#include<vector>

using namespace std;

//Separate method to print the list provided by the calling method
void printElems(vector < int > list) {
    int i;
    int len = list.size();
    for (i = 0; i < len; i++)
        cout << list[i] << "  ";

}

//The Insertion sort logic
void insertionSort(vector < int > & a) {
    int i, loc, temp;
    int len = a.size();

    for (i = 1; i < len; i++) {
        temp = a[i];
        loc = i - 1;

        /* Move elements of arr[0..i-1], that are greater than temp, to one position ahead  
        of their current position as need to bring in the temp to it's correct place */
        while (loc >= 0 && temp < a[loc]) {
            a[loc + 1] = a[loc];
            loc--;
        }

        a[loc + 1] = temp;

        cout << "\n\nThe elements of the list after Pass " << i << " are  : ";
        printElems(a);
    }
}

int main() {
    int i, num, n;

    //Declaring the Vector to store the integer elements to be sorted
    vector < int > v;

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to implement the Insertion Sort algo using Vectors, in CPP  ===== \n\n";

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to sort : ";
    cin >> n;
    cout << "\n\n";

    for (i = 0; i < n; i++) {
        cout << "Enter number" << i + 1 << " :  ";
        cin >> num;
        v.push_back(num);

    }

    cout << "\n\nThe elements of the list before applying the Insertion sort algorithm are : ";

    //Calling the method to print the actual list
    printElems(v);

    //Calling the insertion sort algorithm
    insertionSort(v);

    cout << "\n\nThe elements of the list after applying the Insertion sort algorithm are  : ";

    //Calling the method to print the sorted list
    printElems(v);

    cout << "\n\n\n";

    return 0;
}

输出:

C++ Insertion sort

如有任何疑问,欢迎在下方评论区提问!

继续学习:



C++ 程序:快速排序

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-quick-sort

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现快速排序算法

为了从头开始理解快速排序算法,我们强烈建议您首先访问我们的教程,因为我们已经介绍了它的逐步实现,这里:https://www.studytonight.com/data-structures/quick-sort

代号:

#include <iostream>

#include<vector>

using namespace std;

//Separate method to print the list provided by the calling method
void printElems(vector < int > list) {
    int i;
    int len = list.size();
    for (i = 0; i < len; i++)
        cout << list[i] << "  ";

}

//This function returns the index of the element (pivot) that has been moved to its final position 
int partition_algo(vector < int > & list, int beg, int end) {
    int p = beg, pivot = list[beg], loc;

    //For all the elements following the pivot element
    for (loc = beg + 1; loc <= end; loc++) {
        if (pivot > list[loc]) {
            list[p] = list[loc];
            list[loc] = list[p + 1];
            list[p + 1] = pivot;

            p++;
        }
    }

    return p; //p is the index of the pivot element
}

//The Quick sort logic- making modifications to the actual list itself
void quickSort(vector < int > & list, int beg, int end) {
    if (beg < end) {
        //p stores the index of the pivot element after it gets sorted
        int p = partition_algo(list, beg, end);

        //Applying Quicksort on the elements on Left of the pivot element
        quickSort(list, beg, p - 1);

        //Applying Quicksort on the elements on Right of the pivot element
        quickSort(list, p + 1, end);
    }
}

int main() {
    int i, num, n;

    //Declaring the Vector to store the integer elements to be sorted
    vector < int > v;

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to implement the Quick Sort algo using Vectors, in CPP  ===== \n\n";

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to sort: ";
    cin >> n;
    cout << "\n\n";

    for (i = 0; i < n; i++) {
        cout << "Enter number" << i + 1 << " :  ";
        cin >> num;
        v.push_back(num);

    }

    cout << "\n\nThe elements of the list before applying the Quick sort algorithm are: ";

    //Calling the method to print the actual list
    printElems(v);

    //Calling the Quick sort algorithm for the entire list indexed from 0 to n-1
    quickSort(v, 0, n - 1);

    cout << "\n\nThe elements of the list after applying the Quick sort algorithm are: ";

    //Calling the method to print the sorted list
    printElems(v);

    cout << "\n\n\n";

    return 0;
}

输出:

C++ quick sort

如有任何疑问,欢迎在下方评论区提问!

继续学习:



C++ 程序:归并排序

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-merge-sort

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现归并排序算法

为了从头开始理解归并排序算法,我们强烈建议您首先访问我们的教程,因为我们已经介绍了它的逐步实现,这里:https://www.studytonight.com/data-structures/merge-sort

代号:

#include <iostream>

#include<vector>

using namespace std;

//Separate method to print the list provided by the calling method
void printElems(vector < int > list) {
    int i;
    int len = list.size();
    for (i = 0; i < len; i++)
        cout << list[i] << "  ";

}

//This method is used to merge the two individual sorted lists into a single sorted list
void merge(vector < int > & a, int low, int high, int mid) {
    int i, j, k;

    int c[50];

    i = low;
    k = low;
    j = mid + 1;

    while (i <= mid && j <= high) {
        if (a[i] < a[j]) {
            //copying the elements from arr a to arr c.
            c[k] = a[i];
            k++;
            i++;
        } else {
            //copying the elements from arr a to arr c.
            c[k] = a[j];
            k++;
            j++;
        }
    }
    while (i <= mid) {
        //copying the elements from arr a to arr c.
        c[k] = a[i];
        k++;
        i++;
    }
    while (j <= high) {
        //copying the elements from arr a to arr c.
        c[k] = a[j];
        k++;
        j++;
    }
    for (i = low; i < k; i++) {
        //copying remaining elements from arr c to arr a
        a[i] = c[i];
    }

}

//The recursive Merge Sort logic 
void mergeSort(vector < int > & a, int low, int high) {
    int mid;
    if (low < high) {
        //In Merge sort, the pivot element is always the middle element that divides the list into two equal parts
        mid = (low + high) / 2;

        //Calling Merge sort for the elements on the left of the pivot
        mergeSort(a, low, mid);

        //Calling Merge sort for the elements on the right of the pivot
        mergeSort(a, mid + 1, high);

        //Calling to the merge method to form a single sorted list
        merge(a, low, high, mid);
    }

}

int main() {
    int i, num, n;

    //Declaring the Vector to store the integer elements to be sorted
    vector < int > v;

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to implement the Merge Sort algo using Vectors, in CPP  ===== \n\n";

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to sort : ";
    cin >> n;
    cout << "\n\n";

    for (i = 0; i < n; i++) {
        cout << "Enter number" << i + 1 << " :  ";
        cin >> num;
        v.push_back(num);

    }

    cout << "\n\nThe elements of the list before applying the Merge sort algorithm are : ";

    //Calling the method to print the actual list
    printElems(v);

    //Calling the Merge sort algorithm for the entire list indexed from 0 to n-1
    mergeSort(v, 0, n - 1);

    cout << "\n\nThe elements of the list after applying the Merge sort algorithm are  : ";

    //Calling the method to print the sorted list
    printElems(v);

    cout << "\n\n\n";

    return 0;
}

输出:

C++ Merge sort

如有任何疑问,欢迎在下方评论区提问!

继续学习:



搜索

C++ 程序:二分搜索算法

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-binary-search-algorithm

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现二分搜索算法

为了详细了解二分搜索的概念,我们将推荐您访问https://www . study south . com/data-structures/binary-search-algorithm,我们已经在这里详细解释了这些概念。

为了更好地理解,请参考下面给出的评论良好的 CPP 代码。

代号:

#include <iostream>
#include <vector>
using namespace std;

//Program to return the index of b in the vector a
int BS(int a[], int l, int h, int b)
{
    int res = -1;
    while (l <= h)
    {
        int m = (l + h) / 2;

        if (a[m] == b)
        {
            return m;
        }
        else if (a[m] > b)
        {
            h = m - 1;
        }
        else
        {
            l = m + 1;
        }
    }

    return -1;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Binary Search Algorithm, in CPP  ===== \n\n";

    int i, n;
    int a[] = {2, 3, 5, 8, 9, 10};

    n = sizeof(a) / sizeof(a[0]);

    cout << "\n\nThe elements of the input sorted array are :\n\n";

    for (i = 0; i < n; i++)
    {
        cout << a[i] << "  ";
    }

    int k1 = 8; //the element to find the index of

    //Calling BS() method to return the index of the element k1 if present, else -1.
    int f1 = BS(a, 0, n - 1, k1);

    if (f1 == -1)
    {
        cout << "\n\nThe element " << k1 << " is not present in the given array. ";
    }
    else
    {
        cout << "\n\nThe index of the element " << k1 << " (starting from 0) is: " << f1;
    }

    int k2 = 4; //the element to find the index of

    //Calling BS() method to return the index of the element k2 if present, else -1.
    int f2 = BS(a, 0, n - 1, k2);

    if (f2 == -1)
    {
        cout << "\n\nThe element " << k2 << " is not present in the given array. ";
    }
    else
    {
        cout << "\n\nThe index of the element " << k2 << " (starting from 0) is: " << f2;
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ BS algo

我们希望这篇文章能帮助你更好地理解二分搜索算法的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:DFS 遍历

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-dfs-traversal

大家好!

在本教程中,我们将学习如何用 C++ 编程语言在图上实现 DFS 遍历。

什么是 DFS 遍历?

顾名思义,深度优先搜索算法从起始节点开始,然后遍历图的每个分支,直到找到没有子节点的叶节点。然后,该算法回溯到尚未完全探索的最新节点。重复这个过程,直到图的所有节点都被访问或探索。

DFS 中使用的数据结构是。要了解更多关于栈数据结构的信息,我们建议您访问https://www . study south . com/data-structures/Stack-data-structure,我们已经在这里详细解释了这些概念。

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include<vector>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the DFS Traversal on a Graph, in CPP  ===== \n\n";

    //variable declaration
    int cost[10][10], i, j, k, n, e, top, v, stk[10], visit[10], visited[10];

    cout << "Enter the number of vertices in the Graph: ";
    cin >> n;
    cout << "\nEnter the number of edges in the Graph : ";
    cin >> e;
    cout << "\nEnter the start and end vertex of the edges: \n";

    for (k = 1; k <= e; k++)
    {
        cin >> i >> j;
        cost[i][j] = 1;
    }

    cout << "\nEnter the initial vertex to start the DFS traversal with: ";
    cin >> v;
    cout << "\nThe DFS traversal on the given graph is : \n";
    cout << v << " ";

    //As we start with the vertex v, marking it visited to avoid visiting again
    visited[v] = 1;

    k = 1;

    //The DFS Traversal Logic
    while (k < n)
    {
        for (j = n; j >= 1; j--)
        {
            if (cost[v][j] != 0 && visited[j] != 1 && visit[j] != 1)
            {
                visit[j] = 1;

                //put all the vertices that are connected to the visited vertex into a stack
                stk[top] = j;
                top++;
            }
        }

        //output all the connected vertices one at a time
        v = stk[--top];
        cout << v << " ";
        k++;

        //as v is visited so it is not a valid candidate to visit in future so visit[v]=0 and visited[v]=1
        visit[v] = 0;

        //to mark it visited 
        visited[v] = 1;
    }

        cout << "\n\n\n";

    return 0;
} 

输出:

C++ DFS Traversal

我们希望这篇文章能帮助您更好地理解 DFS 遍历的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:BFS 遍历

原文:https://www.studytonight.com/cpp-programs/cpp-program-for-bfs-traversal

大家好!

在本教程中,我们将学习如何用 C++ 编程语言在图形上实现BFS 遍历。

什么是 BFS 遍历?

顾名思义,广度优先搜索(DFS)算法从起始节点开始,然后遍历图的每个分支,直到我们所有的节点都被探索至少一次。

该算法在移动到下一深度级别的节点之前,探索当前深度的所有相邻节点

BFS 使用的数据结构是队列。要了解更多关于队列数据结构的信息,我们建议您访问队列数据结构,在这里我们已经详细解释了这些概念。

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

vector<bool> v;
vector<vector<int>> g;

void bfsTraversal(int b)
{
    //Declare a queue to store all the nodes connected to b
    queue<int> q;

    //Insert b to queue
    q.push(b);

    //mark b as visited
    v[b] = true;

    cout << "\n\nThe BFS Traversal is:  ";

    while (!q.empty())
    {
        int a = q.front();
        q.pop(); //delete the first element form queue

        for (auto j = g[a].begin(); j != g[a].end(); j++)
        {
            if (!v[*j])
            {
                v[*j] = true;
                q.push(*j);
            }
        }
        cout << a << "  ";
    }
}

void makeEdge(int a, int b)
{
    g[a].push_back(b); //an edge from a to b (directed graph)
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Breadth First Search Algorithm, in CPP  ===== \n\n";

    cout << " =====  Note; The vertices are numbered from 0 to n-1\.  ===== \n\n";

    int n, e;

    cout << "Enter the number of vertices: ";

    cin >> n;

    cout << "\n\nEnter the number of edges: ";

    cin >> e;

    v.assign(n, false);
    g.assign(n, vector<int>());

    int a, b, i;

    cout << "Enter the edges with source and target vetex: \n ";

    for (i = 0; i < e; i++)
    {
        cin >> a >> b;
        makeEdge(a, b);
    }

    for (i = 0; i < n; i++)
    {
        //if the node i is unvisited
        if (!v[i])
        {
            bfsTraversal(i);
        }
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ BFS Traversal

我们希望这篇文章能帮助你更好地理解 BFS 遍历的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用修改的二分搜索查找给定数字的第一次出现

原文:https://www.studytonight.com/cpp-programs/cpp-find-first-occurrence-of-the-given-number-using-modified-binary-search

大家好!

在本教程中,我们将学习如何用 C++ 编程语言在排序数组中找到给定数字的第一次出现。

要详细了解二分搜索的概念,我们将推荐您访问二分搜索算法,我们已经在这里详细解释了这些概念。

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Program to return the first occurance of b in the vector a
int first(int a[], int l, int h, int b)
{
    int res = -1;
    while (l <= h)
    {
        int m = (l + h) / 2;

        if (a[m] == b)
        {
            res = m;
            h = m - 1;
        }
        else if (a[m] > b)
        {
            h = m - 1;
        }
        else
        {
            l = m + 1;
        }
    }

    return res;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the first occurance of a given number using Modified Binary Search  ===== \n\n";

    int i, n;

    int a[] = {2, 3, 3, 4, 4, 4, 4, 4, 5};

    n = sizeof(a) / sizeof(a[0]);

    cout << "\n\nThe elements of the input sorted array are :\n\n";

    for (i = 0; i < n; i++)
    {
        cout << a[i] << "  ";
    }

    int k = 4; //the element to find the first occurance index of

    //Calling first method to return the index of the first occurance of element k
    int f = first(a, 0, n - 1, k);

    cout << "\n\nThe index of the first occurance of " << k << " is: " << f;

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ BS algo first

我们希望这篇文章能帮助你更好地理解二分搜索算法的概念,并使用它来找到给定数字的第一次出现及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用修改的二分搜索查找给定数字的最后一次出现

原文:https://www.studytonight.com/cpp-programs/cpp-find-last-occurrence-of-the-given-number-using-modified-binary-search

大家好!

在本教程中,我们将学习如何用 C++ 编程语言在排序数组中找到给定数字的最后一次出现。

为了详细了解二分搜索的概念,我们将推荐您访问https://www . study south . com/data-structures/binary-search-algorithm,我们已经在这里详细解释了这些概念。

为了更好地理解,请参考下面给出的评论良好的 CPP 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Program to return the last occurance of b in the vector a
int last(int a[], int l, int h, int b)
{
    int res = -1;
    while (l <= h)
    {
        int m = (l + h) / 2;

        if (a[m] == b)
        {
            res = m;
            l = m + 1;
        }
        else if (a[m] > b)
        {
            h = m - 1;
        }
        else
        {
            l = m + 1;
        }
    }

    return res;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the last occurance of a given number using Modified Binary Search  ===== \n\n";

    int i, n;

    int a[] = {2, 3, 3, 4, 4, 4, 4, 4, 5};

    n = sizeof(a) / sizeof(a[0]);

    cout << "\n\nThe elements of the input sorted array are :\n\n";

    for (i = 0; i < n; i++)
    {
        cout << a[i] << "  ";
    }

    int k = 4; //the element to find the last occurance index of

    //Calling first method to return the index of the last occurance of element k
    int l = last(a, 0, n - 1, k);

    cout << "\n\nThe index of the last occurance of " << k << " is: " << l;

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ BS algo last

我们希望这篇文章能帮助您更好地理解二分搜索算法的概念,并使用它来查找给定数字的最后一次出现及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



面向对象的程序设计

C++ 程序:面向对象类示例

原文:https://www.studytonight.com/cpp-programs/cpp-program-with-oop-class-example

大家好!

在本教程中,我们将学习如何用 C++ 编程语言实现类及其成员的概念。

要了解类及其成员的概念,我们将推荐您访问这里:c++ 类的概念,我们已经从头开始解释了。

代号:

#include <iostream>
#include <vector>

using namespace std;

class studyTonight {

    //variable declaration- can be used only within the class as it's declared private
    private:
        int value;

    //Public methods can be called from anywhere- inside as well as outside the class
    public:
        void input() {
            cout << "Entering the input() function\n";
            cout << "Enter an integer you want to display: ";
            cin >> value;
            cout << "Exiting the input() function\n\n";
        }

    void display() {

        cout << "\nEntering the display() function\n";
        cout << "The value entered is: ";
        cout << value;
        cout << "\nExiting the display() function\n\n";
    }
};

int main() {
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Class, in CPP  ===== \n\n";

    //Declaring class object to access class members from outside the class
    studyTonight object;

    cout << "\n\nCalling the input() function from the main() method\n\n\n";
    object.input();

    cout << "\nCalling the display() function from the main() method\n\n\n";

    object.display();

    cout << "\n\nExiting the main() method\n\n\n";

    //object.value- This will produce an error because variable is declared to be private and hence cannot be accessed from outside the class

    return 0;
}

输出:

C++ Class

我们希望这篇文章能帮助你更好地理解 C++ 中类及其成员的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用类执行基本操作

原文:https://www.studytonight.com/cpp-programs/cpp-performing-basic-operations-using-class

大家好!

在本教程中,我们将学习如何使用 C++ 编程语言中的类及其成员执行基本操作。

为了了解类及其成员的概念,我们将推荐您访问这里: C++ 类概念,我们已经从头开始解释了。

代号:

#include <iostream>

#include <vector>

using namespace std;

//defining the class operations to implement all the basic operations
class operations {
    //declaring member variables
    public:
        int num1, num2;

    //defining member function or methods
    public:
        void input() {
            cout << "Enter two numbers to perform operations on: \n";
            cin >> num1 >> num2;
            cout << "\n";
        }

    public:
        void addition() {
            cout << "Addition = " << num1 + num2;
            cout << "\n";
        }

    void subtraction() {
        cout << "Subtraction = " << num1 - num2;
        cout << "\n";
    }

    void multiplication() {
        cout << "Multiplication = " << num1 * num2;
        cout << "\n";
    }

    void division() {
        cout << "Division = " << (float) num1 / num2;
        cout << "\n";
    }
};

//Defining the main method to access the members of the class
int main() {
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to perform basic operations using Class, in CPP  ===== \n\n";

    //Declaring class object to access class members from outside the class
    operations op;

    cout << "\nCalling the input() function from the main() method\n";
    op.input();

    cout << "\nCalling the addition() function from the main() method\n";
    op.addition();

    cout << "\nCalling the subtraction() function from the main() method\n";
    op.subtraction();

    cout << "\nCalling the multiplication() function from the main() method\n";
    op.multiplication();

    cout << "\nCalling the division() function from the main() method\n";
    op.division();

    cout << "\nExiting the main() method\n\n\n";

    return 0;
}

输出:

C++ Class operations

我们希望这篇文章能帮助你更好地理解 C++ 中类的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:多态示例

原文:https://www.studytonight.com/cpp-programs/cpp-polymorphism-example-program

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中实现多态的概念。

为了理解 CPP 中多态的概念,我们将推荐您访问这里:函数覆盖,我们已经从头开始解释了。

代号:

#include <iostream>

using namespace std;

//defining the class Addition to overload the method sumOf() to explain the concept of Polymorphism
class Addition {

    public:
        int sumOf(int n1, int n2) {
            cout << "\nPerforming the addition operation on two integers and the value returned is: ";
            return n1 + n2;
        }
    int sumOf(int n1, int n2, int n3) {
        cout << "\nPerforming the addition operation on three integers and the value returned is: ";
        return n1 + n2 + n3;
    }
    int sumOf(int n1, int n2, int n3, int n4) {
        cout << "\nPerforming the addition operation on four integer values and the value returned is: ";
        return n1 + n2 + n3 + n4;
    }
};

//Defining the main method to access the members of the class
int main() {

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to explain the concept of Polymorphism, in CPP  ===== \n\n";

    Addition add; //Default constructor is called- which is not required to be written explicitly

    cout << add.sumOf(3, 5) << "\n\n";
    cout << add.sumOf(3, 5, 10) << "\n\n";
    cout << add.sumOf(3, 5, 7, 10) << "\n\n";

    cout << "\n\nExiting the main() method\n\n\n";

    return 0;
}

输出:

C++ polymorphism

我们希望这篇文章能帮助你更好地理解 C++ 中多态的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:方法重载

原文:https://www.studytonight.com/cpp-programs/cpp-method-overloading-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示方法重载的概念。

为了理解 CPP 中方法或函数重载的概念,我们将推荐您访问这里:函数覆盖,我们已经从头开始解释了。

代号:

#include <iostream>

#include <vector>

using namespace std;

//defining the class shape to overload the method area() on the basis of number of parameters.
class shape {

    //declaring member variables
    public:
        int l, b, s;

    //defining member function or methods
    public:
        void input() {
            cout << "Enter the length of each side of the Square: \n";
            cin >> s;
            cout << "\n";
            cout << "Enter the length and breadth of the Rectangle: \n";
            cin >> l >> b;
            cout << "\n";
        }

    //Demonstrating Method Overloading
    public:
        void area(int side) {
            cout << "Area of Square = " << side * side;
            cout << "\n";
        }

    void area(int length, int breadth) {
        cout << "Area of Rectangle = " << length * breadth;
        cout << "\n";
    }
};

//Defining the main method to access the members of the class
int main() {
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate Method Overloading in a Class, in CPP  ===== \n\n";

    //Declaring class object to access class members from outside the class
    shape sh;

    cout << "\nCalling the input() function to take the values from the user\n";
    sh.input();

    cout << "\nCalling the area(int) function to calculate the area of the Square\n";
    sh.area(sh.s);

    cout << "\nCalling the area(int,int) function to calculate the area of the Rectangle\n";
    sh.area(sh.l, sh.b);

    cout << "\nExiting the main() method\n\n\n";

    return 0;
}

输出:

C++ method overloading

我们希望这篇文章能帮助你更好地理解 C++ 中方法重载的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:构造器和析构器示例

原文:https://www.studytonight.com/cpp-programs/cpp-constructor-and-destructor-example-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示构造器和析构器的概念。

为了理解 CPP 中构造器和析构器的概念,我们将推荐您访问这里: C++ 构造器和析构器,我们已经从头开始解释了。

代号:

#include <iostream>

using namespace std;

//Rectangle class to demonstrate the working of Constructor and Destructor in CPP
class Rectangle {
    public:
        float length, breadth;

    //Declaration of the default Constructor of the Rectangle Class
    public:
        Rectangle() {
            cout << "\n\n****** Inside the Constructor ******* \n\n";
            length = 2;
            breadth = 4;
        }

    //Declaration of the Destructor of the Rectangle Class
    public:
        ~Rectangle() {
            cout << "\n\n****** Inside the Destructor ******* \n\n";
        }
};

//Defining the main method to access the members of the class
int main() {

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Constructor and Destructor in CPP  ===== \n\n";

    cout << "\nCalling the default Constructor of the Rectangle class to initialize the object.\n\n";

    //Declaring the Class object to access the class members
    Rectangle rect;

    cout << "\nThe Length of the Rectangle set by the Constructor is = " << rect.length << "\n\n";

    cout << "\nThe Breadth of the Rectangle set by the Constructor is = " << rect.breadth << "\n\n";

    return 0;
}

输出:

C++ constructor and destructor

我们希望这篇文章能帮助你更好地理解 C++ 中构造器和析构器的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:构造器重载

原文:https://www.studytonight.com/cpp-programs/cpp-constructor-overloading-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示构造器重载的概念。

为了理解 CPP 中构造器重载的概念,我们将推荐您访问这里:https://www . study south . com/CPP/constructors-and-destructors-in-CPP . PHP,我们已经从头开始解释了。

代号:

#include <iostream>
#include <vector>
using namespace std;

//defining the class shape to overload the method area() on the basis of number of parameters.
class Area
{

    //declaring member variables
private:
    int length, breadth;

public:
    // Constructor without argument
    Area() : length(5), breadth(2)
    {
    }

    // Defining a Constructor with two arguments: length and breadth
    Area(int l, int b) : length(l), breadth(b)
    {
    }

    void GetLength()
    {
        cout << "\nEnter the Length and Breadth of the Rectangle : \n";
        cin >> length >> breadth;
    }

    int AreaCalculation()
    {
        return (length * breadth);
    }

    void DisplayArea(int a)
    {
        cout << "Area of the Rectangle is = " << a << endl;
    }
};

//Defining the main method to access the members of the class
int main()
{

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate Constructor Overloading in a Class, in CPP  ===== \n\n";

    Area a1; //Default constructor is called

    Area a2(5, 2); //Parameterised constructor is called

    int area1, area2;

    a1.GetLength();

    cout << "\n\nCalculating Area using a Default Constructor:" << endl;

    area1 = a1.AreaCalculation();
    a1.DisplayArea(area1);

    cout << "\n\nCalculating Area using a Parameterised Constructor:" << endl;

    area2 = a2.AreaCalculation();
    a2.DisplayArea(area2);

    cout << "\n\nExiting the main() method\n\n\n";

    return 0;
} 

输出:

C++ constructor overloading

我们希望这篇文章能帮助你更好地理解 C++ 中构造器重载的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:单层继承

原文:https://www.studytonight.com/cpp-programs/cpp-single-level-inheritance-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示单级继承的概念。

为了理解 CPP 中继承和各种访问修饰符的概念,我们将推荐您访问这里: C++ 继承,我们已经从头开始解释了。

代号:

#include <iostream>

using namespace std;

//Class Shape to compute the Area and Perimeter of the Shape it derives
class Shape {
    public:
        float area(float l, float b) {
            return (l * b);
        }

    public:
        float perimeter(float l, float b) {
            return (2 * (l + b));
        }
};

//Rectangle class inherites or is derived from the parent class: Shape.
class Rectangle: private Shape {
    private: float length,
    breadth;

    //Default Constructor of the Rectangle Class
    public: Rectangle(): length(0.0),
    breadth(0.0) {}

    void getDimensions() {
        cout << "\nEnter the length of the Rectangle: ";
        cin >> length;

        cout << "\nEnter the breadth of the Rectangle: ";
        cin >> breadth;
    }

    //Method to Calculate the perimeter of the Rectangle by using the Shape Class
    float perimeter() {
        //Calls the perimeter() method of class Shape and returns it.
        return Shape::perimeter(length, breadth);
    }

    //Method to Calculate the area of the Rectangle by using the Shape Class
    float area() {
        //Calls the area() method of class Shape and returns it.
        return Shape::area(length, breadth);
    }
};

//Defining the main method to access the members of the class
int main() {

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Single Level Inheritence in CPP  ===== \n\n";

    //Declaring the Class objects to access the class members
    Rectangle rect;
    cout << "\nClass Rectangle inherites the Shape Class or Rectangle class is derieved from the Shape class.\n\n";

    cout << "\nCalling the getDimensions() method from the main() method:\n\n";

    rect.getDimensions();
    cout << "\n\n";

    cout << "\nPerimeter of the Rectangle computed using the parent Class Shape is : " << rect.perimeter() << "\n\n\n";
    cout << "Area of the Rectangle computed using the parent Class Shape is: " << rect.area();

    cout << "\n\n\n";

    return 0;
}

输出:

C++ single level inheritence

我们希望这篇文章能帮助你更好地理解 C++ 中继承和访问修饰符的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:多级继承

原文:https://www.studytonight.com/cpp-programs/cpp-multi-level-inheritance-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示多级继承的概念。

要了解 CPP 中多级继承的概念,我们将推荐您访问这里: C++ 类型的继承,我们已经从头开始解释了。

代号:

#include <iostream>

using namespace std;

//Class Volume to compute the Volume of the Cuboid
class Volume {
    public:
        float volume(float l, float b, float h) {
            return (l * b * h);
        }
};

//Class Area to compute the Volume of the Cuboid
class Area {
    public:
        float area(float l, float b, float h) {
            return (2 * (l * b + l * h + b * h));
        }
};

//Cuboid class inherites or is derived from two different classes Volume and Area.
class Cuboid: private Volume, private Area {
    private: float length,
    breadth,
    height;

    //Default Constructor of the Cuboid Class
    public: Cuboid(): length(0.0),
    breadth(0.0),
    height(0.0) {}

    void getDimensions() {
        cout << "\nEnter the length of the Cuboid: ";
        cin >> length;

        cout << "\nEnter the breadth of the Cuboid: ";
        cin >> breadth;

        cout << "\nEnter the height of the Cuboid: ";
        cin >> height;
    }

    //Method to Calculate the area of the Cuboid by using the Area Class
    float volume() {
        //Calls the volume() method of class Volume and returns it.
        return Volume::volume(length, breadth, height);
    }

    //Method to Calculate the area of the Cuboid by using the Area Class
    float area() {
        //Calls the area() method of class Area and returns it.
        return Area::area(length, breadth, height);
    }
};

//Defining the main method to access the members of the class
int main() {

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Multiple Level Inheritence in CPP  ===== \n\n";

    //Declaring the Class objects to access the class members
    Cuboid cuboid;

    cout << "\nCalling the getDimensions() method from the main() method:\n\n";

    cuboid.getDimensions();
    cout << "\n\n";

    cout << "\nArea of the Cuboid computed using Area Class is : " << cuboid.area() << "\n\n\n";
    cout << "Volume of the Cuboid computed using Volume Class is: " << cuboid.volume();

    cout << "\n\n\n";

    return 0;
}

输出:

C++ multi level inheritence

我们希望这篇文章能帮助你更好地理解 C++ 中多级继承的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:层次继承

原文:https://www.studytonight.com/cpp-programs/cpp-hierarchical-inheritance-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示层次继承的概念。

为了理解 CPP 中的层次继承的概念,我们将推荐您访问这里: C++ 类型的继承,我们已经从头开始解释了它。

代号:

#include <iostream>

using namespace std;

//defining the class Shape to demonstrate the concept of Hierarchial Inheritence in CPP
class Shape {
    //protected member variables are only accessible within the class and its descendent classes
    protected:
        float width, height;

    //public members are accessible everywhere
    public:
        void setDimensions(float w, float h) {
            cout << "Setting the Dimensions using the parent Class: Shape\n";
            cout << "The dimensions are: " << w << " and " << h << "\n\n";

            width = w;
            height = h;
        }
};

//Class Rectangle inherites the Shape class
class Rectangle: public Shape {
    //Method Overriding
    public: float area() {
        return (width * height);
    }
};

//Class Triangle inherites the Shape class
class Triangle: public Shape {
    //Method Overriding
    public: float area() {
        return (width * height / 2);
    }
};

//Defining the main method to access the members of the class
int main() {

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Hierarchial Inheritence in CPP  ===== \n\n";

    //Declaring the Class objects to access the class members
    Rectangle rectangle;
    Triangle triangle;

    rectangle.setDimensions(5, 3);
    triangle.setDimensions(2, 5);

    cout << "\nArea of the Rectangle computed using Rectangle Class is : " << rectangle.area() << "\n\n\n";
    cout << "Area of the Triangle computed using Triangle Class is: " << triangle.area();

    cout << "\n\n\n";

    return 0;
}

输出:

C++ hierarchial Inheritence

我们希望这篇文章能帮助你更好地理解 C++ 中层次继承的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:友元函数

原文:https://www.studytonight.com/cpp-programs/cpp-friend-function-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示友元函数的概念。

要了解 CPP 中友元函数的概念和其他各种类型的类成员函数,我们将推荐您访问这里: C++ 类型的成员函数,我们已经从头解释过了。

代号:

#include <iostream>

using namespace std;

//Class Volume to demonstrate the concept of Friend Function in CPP
class Volume {
    //Member variables are declared as private and hence cannot be simply accessed from outside the class
    private:
        int liter;

    //Initializing the value of variable liter to 2 using the default constructor
    public:
        Volume(): liter(2) {}

    //Declaring the Friend Function for the class Volume
    friend int mulFive(Volume);
};

// Defining the Friend Function to be used by the Volume Class
int mulFive(Volume v) {
    //Friend function enables accessing private data from non-member function
    v.liter *= 5;
    return v.liter;
}

//Defining the main method to access the members of the class
int main() {

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of a Friend Function in CPP  ===== \n\n";

    //Declaring the Class objects to access the class members
    Volume vol;

    cout << "Volume after calling the Friend Function = " << mulFive(vol);

    cout << "\n\n\n";

    return 0;
}

输出:

C++ friend function

我们希望这篇文章能帮助你更好地理解 C++ 中友元函数的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:加号(+)运算符重载

原文:https://www.studytonight.com/cpp-programs/cpp-plus-operator-overloading-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示+运算符重载的概念。

要了解 CPP 中运算符重载的概念,我们将推荐您访问这里: C++ 运算符重载,我们已经从头开始解释了。

代号:

#include <iostream>

using namespace std;

//defining the class Cuboid to demonstrate the concept of Plus Operator Overloading in CPP
class Cuboid {
    //Declaring class member variables as public to access from outside the class
    public:
        double length; // Length of Cuboid
    double breadth; // Breadth of Cuboid
    double height; // Height of Cuboid

    public:
        double getVolume(void) {
            return length * breadth * height;
        }
    void setLength(double l) {
        length = l;
    }

    void setBreadth(double b) {
        breadth = b;
    }

    void setHeight(double h) {
        height = h;
    }

    // Overload + operator to add two Cuboid objects with each other.
    Cuboid operator + (const Cuboid & c) {
        Cuboid cuboid;
        cuboid.length = this -> length + c.length;
        cuboid.breadth = this -> breadth + c.breadth;
        cuboid.height = this -> height + c.height;
        return cuboid;
    }
};

//Defining the main method to access the members of the class
int main() {

    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Plus Operator Overloading, in CPP  ===== \n\n";

    //Declaring the Class objects to access the class members
    Cuboid c1;
    Cuboid c2;
    Cuboid c3;

    //To store the volume of the Cuboid
    double volume = 0.0;

    // Setting the length, breadth and height for the first Cuboid object: c1
    c1.setLength(3.0);
    c1.setBreadth(4.0);
    c1.setHeight(5.0);

    // Setting the length, breadth and height for the second Cuboid object: c2
    c2.setLength(2.0);
    c2.setBreadth(5.0);
    c2.setHeight(8.0);

    // Finding the Volume of the first Cuboid: c1
    cout << "Calling the getVolume() method to find the volume of Cuboid c1\n";
    volume = c1.getVolume();
    cout << "Volume of the Cuboid c1 is : " << volume << "\n\n\n";

    // Finding the Volume of the first Cuboid: c1
    cout << "Calling the getVolume() method to find the volume of Cuboid c2\n";
    volume = c2.getVolume();
    cout << "Volume of the Cuboid c2 is : " << volume << "\n\n\n";

    // Adding the two Cuboid objects c1 and c2 to form the third object c3:
    c3 = c1 + c2;

    // Printing the dimensions of the third Cuboid: c3
    cout << "Length of the Cuboid c3 is : " << c3.length << endl;
    cout << "Breadth of the Cuboid c3 is : " << c3.breadth << endl;
    cout << "Height of the Cuboid c3 is : " << c3.height << endl;

    // Finding the Volume of the third Cuboid: c3
    cout << "\n\nCalling the getVolume() method to find the volume of Cuboid c3\n";
    volume = c3.getVolume();
    cout << "Volume of the Cuboid c3 is : " << volume << endl;
    cout << "\n\n\n";

    return 0;
}

输出:

C++ plus operator overloading

我们希望这篇文章能帮助你更好地理解 C++ 中运算符重载的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



文件处理

C++ 程序:从文件中读取

原文:https://www.studytonight.com/cpp-programs/cpp-reading-from-a-file-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言打开并读取文件的内容。

为了从基础上理解这个概念,我们强烈建议您参考这个: C++ 文件流,在这里我们详细讨论了这个概念以及其中涉及的各种术语。

分步注释代码如下所示:

代号:

#include<iostream>
#include<fstream>  //to make use of system defined functions for file handling

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate how to read the contents from a file ===== \n\n";

    //declaration of a string variable
    string str;

    // creating a variable of type ifstream to make use of file handling commands and open a file in read mode.
    ifstream in;

    //open is a system defined method to open and read from the mentioned file
    in.open("studytonight.txt");

    //Make sure that the file is within the same folder as that of this program otherwise, will have to provide the entire path to the file to read from

    cout << "Reading content from the file and it's contents are: \n\n";

    // printing the data word by word
    while(in>>str)
        cout << str << " ";

    cout << "\n\n\n";

    // close the file opened before.
    in.close();

    return 0;
}

study south . txt文件的内容是:

Studytonight: Our mission is to empower young Students to be the inventors and creators.

输出:

C++ read from a file

我们希望这篇文章能帮助你更好地理解用 C++ 从文件中读取内容的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



标准模板库

C++ 程序:使用 STL 初始化向量(第一部分)

原文:https://www.studytonight.com/cpp-programs/cpp-program-initialising-a-vector-in-stl-part-1

大家好!

在本教程中,我们将学习用 C++ 编程语言初始化向量的各种方法。

什么是向量?

向量与动态数组相同,能够在插入或删除元素时自动调整自身大小。这使得它们比固定大小且本质上是静态的普通数组更有优势。

要了解更多关于 CPP 中的向量,我们将推荐您访问 STL 向量容器

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include<iostream>
#include<bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the various ways of Initializing a Vector (Part 1), in CPP  ===== \n\n";

    cout << "Method 1: Using push_back() method\n\n";

    //create an empty vector
    vector<int> v;

    //insert elements into the vector
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    //prining the vector
    cout << "The elements of the first vector are: ";

    for (int i : v)
    {
        cout << i << " ";
    }

    cout << "\n\n\n\n\nMethod 2: Initializing all the elements with a specific value\n\n";

    //creating a vector of size 5 with all values initalized to 10
    vector<int> v1(5, 10);

  //prining the vector
    cout << "The elements of the second vector are: ";
     for (int i : v1)
    {
        cout << i << " ";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Vector Initialization

我们希望这篇文章能帮助你更好地理解向量的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 初始化向量(第二部分)

原文:https://www.studytonight.com/cpp-programs/cpp-initializing-a-vector-in-stl-part-2-program

大家好!

在本教程中,我们将学习用 C++ 编程语言初始化向量的各种方法。

什么是向量?

向量与动态数组相同,能够在插入或删除元素时自动调整自身大小。这使得它们比固定大小且本质上是静态的普通数组更有优势。

要了解更多关于 CPP 中的向量,我们将推荐您访问 C++ STL 向量

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the various ways of Initializing a Vector (Part 2), in CPP  ===== \n\n";

    cout << "Method 1: Initialize a Vector like an Array\n\n";

    //create and initialize a vector
    vector<int> v{1, 2, 3, 4};

    //prining the vector
    cout << "The elements of the first vector are: ";

    for (int i : v)
    {
        cout << i << " ";
    }

    cout << "\n\n\nMethod 2: Initializing a Vector from an Array\n\n";

    //creating and initializing an array
    int a[] = {11, 22, 33};

    //calculating number of elements in an array
    int n = sizeof(a) / sizeof(a[0]);

    //creating and initializing a vector with the array elements
    vector<int> v1(a, a + n);

    //prining the vector
    cout << "The elements of the second vector are: ";
    for (int i : v1)
    {
        cout << i << " ";
    }

    cout << "\n\n\nMethod 3: Initializing a Vector from another Vector\n\n";

    //creating and initializing the source vector
    vector<int> a1 = {10, 22, 33};

    //creating and initializing a second vector with the elements of the first vector
    vector<int> b(a1.begin(), a1.end());

    //prining the vector
    cout << "The elements of the third vector are: ";
    for (int i : b)
    {
        cout << i << " ";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Vector Initialization  part 2

我们希望这篇文章能帮助你更好地理解向量的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在旋转排序向量中寻找最小元素

原文:https://www.studytonight.com/cpp-programs/cpp-find-minimum-element-in-a-rotated-sorted-vector-program

大家好!

在本教程中,我们将演示 C++ 编程语言中在旋转排序向量中寻找最小元素的逻辑。

什么是旋转排序向量?

旋转排序向量是一个排序向量,它在你事先不知道的某个轴元素上旋转。

示例: [4,5,6,7,0,1,2] 是排序向量[0,1,2,4,5,6,7]的旋转排序向量之一。

为了更好地理解它的实现,请参考下面给出的评论很好的 CPP 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int findMin(vector<int> &m)
{
    int i;
    int n = m.size();
    for (i = 0; i < n; i++)
    {
        if (i == 0)
        {
            if (m[i] < m[n - 1] && m[i] < m[1])
                break;
        }
        else
        {
            if (m[i] < m[i - 1] && m[i] < m[(i + 1) % n])
                break;
        }
    }

    return m[i % n];
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " ===== Program to find the Minimum element in a rotated Sorted Vector, in CPP  ===== \n\n\n";

    cout << " ===== Logic: The minimum element will have larger number on both right and left of it.   ===== \n\n\n";

    //initializing vector with the following elements
    vector<int> v = {4, 5, 6, 7, 1, 3, 2};

    int n = v.size();

    int mini = 0;

    cout << "The elements of the given vector is : ";

    for (int i = 0; i < n; i++)
    {
        cout << v[i] << "  ";
    }

    mini = findMin(v);

    cout << "\n\nThe Minimum element in the given vector is: " << mini;

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ rotated sorted vector

我们希望这篇文章能帮助你更好地理解在旋转排序向量中寻找最小元素的概念及其在 CPP 中的实现。如有任何疑问,请通过下面的评论部分与我们联系。

继续学习:



C++ 程序:在 STL 向量中使用lower_bound()方法

原文:https://www.studytonight.com/cpp-programs/cpp-program-using-lower_bound-method-in-vector-stl

大家好!

在本教程中,我们将学习 STL 中 lower_bound() 方法的工作原理,以及它在 C++ 编程语言中使用矢量的实现。

什么是向量?

向量与动态数组相同,能够在插入或删除元素时自动调整自身大小。这使得它们比固定大小且本质上是静态的普通数组更有优势。

要了解更多关于 CPP 中的向量,我们将推荐您访问 C++ STL 向量

lower_bound()方法:

lower_bound()方法返回一个指向第一个元素的迭代器,该元素的值不小于给定值

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of lower_bound() method of STL, in CPP  ===== \n\n";

    cout << "\n\nDeclaring a Vector and Filling it with integers.\n\n";

    //create an empty vector
    vector<int> v;

    //insert elements into the vector
    v.push_back(10);
    v.push_back(12);
    v.push_back(35);
    v.push_back(65);
    v.push_back(21);
    v.push_back(90);

    //prining the vector
    cout << "The elements of the Vector are: ";

    //Another way of printing the elements using the for loop
    for (int i : v)
    {
        cout << i << " ";
    }

    //Sorting the vector in ascending order
    sort(v.begin(), v.end());

    //prining the Sorted vector
    cout << "\n\nThe elements of the Vector after Sorting are: ";

    for (int i : v)
    {
        cout << i << " ";
    }

    vector<int>::iterator low;

    low = lower_bound(v.begin(), v.end(), 35);

    cout << "\n\nlower_bound returns an iterator pointing to the first element which has a value not less than the given value.";

    cout << "\n\nThe index (starting from 0) of the lower_bound of 35 is: " << (low - v.begin()) << '\n';

    cout << "\n\nNote that as per the definition, it also considers the number itself.\n";

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ lower bound

我们希望这篇文章能帮助您更好地理解下界()方法的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 向量中使用upper_bound()方法

原文:https://www.studytonight.com/cpp-programs/cpp-program-using-upper_bound-method-in-vector-stl

大家好!

在本教程中,我们将学习 STL 中的 upper_bound()方法的工作原理,以及它在 C++ 编程语言中使用 Vector 的实现。

什么是向量?

向量与动态数组相同,能够在插入或删除元素时自动调整自身大小。这使得它们比普通的固定大小的静态数组更先进。

要了解更多关于 CPP 中的向量,我们将推荐您访问 C++ STL 向量

upper_bound()方法:

upper_bound()方法是一个迭代器,指向第一个元素,该元素的值大于给定值

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of upper_bound() method of STL, in CPP  ===== \n\n";

    cout << "\n\nDeclaring a Vector and Filling it with integers.\n\n";

    //create an empty vector
    vector<int> v;

    //insert elements into the vector
    v.push_back(10);
    v.push_back(12);
    v.push_back(35);
    v.push_back(65);
    v.push_back(21);
    v.push_back(90);

    //prining the vector
    cout << "The elements of the Vector are: ";

    vector<int>::iterator it;

    //Printing the elements using an iterator
    for (it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }

    //Sorting the vector in ascending order
    sort(v.begin(), v.end());

    //prining the Sorted vector
    cout << "\n\nThe elements of the Vector after Sorting are: ";

    //Another way of printing the elements of a vector
    for (int i : v)
    {
        cout << i << " ";
    }

    vector<int>::iterator up;

    up = upper_bound(v.begin(), v.end(), 35);

    cout << "\n\nupper_bound returns an iterator pointing to the first element which has a value greater than the given value.";

    cout << "\n\nThe index (starting from 0) of the upper_bound of 35 is: " << (up - v.begin()) << '\n';

    cout << "\n\nNote that as per the definition, it only considers the numbers greater than it and not itself.\n";

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ upper bound

我们希望这篇文章能帮助你更好地理解upper_bound()方法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 列表(第一部分)

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-lists-part-1-program

大家好!

在本教程中,我们将学习 C++ 编程语言中列表(第一部分)的工作方式。

为了理解 C++ 中列表的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-list,在那里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的评论良好的 CPP 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the list
void show(list<int> &l)
{
    //Defining an iterator for the list
    list<int>::iterator i;

    for (i = l.begin(); i != l.end(); i++)
    {
        cout << "\t" << *i;
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of Lists (Part 1), in CPP  ===== \n\n";

    int i;

    //List declaration (list of integers)
    list<int> l1, l2;

    //Filling the elements
    cout << "Filling both the lists in two possible ways: from front and from back\n\n";
    for (i = 0; i < 5; i++)
    {
        l1.push_back(i * 10);  //inserting elements from end
        l2.push_front(i * 20); //inserting elements from front
    }

    cout << "List 1 whose element is inserted from end is: ";
    show(l1);

    cout << "\n\nList 1 whose element is inserted from front is: ";
    show(l2);

    cout << "\n\nThe first element of the list 1 is :  " << l1.front();

    cout << "\n\nThe last element of the list 2 is :  " << l2.back();

    cout << "\n\nAfter deleting the first element of list 1, it becomes: ";
    l1.pop_front();
    show(l1);

    cout << "\n\nAfter deleting the last element of list 2, it becomes: ";
    l2.pop_back();
    show(l2);

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Lists Part 1

我们希望这篇文章能帮助你更好地理解列表的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 列表(第 2 部分)

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-lists-part-2-program

大家好!

在本教程中,我们将学习 C++ 编程语言中列表(第 2 部分)的工作方式。

我们已经解释并实现了列表上的各种功能,如reverse()``sort()``push_back()``push_front()等。

**为了理解 C++ 中列表的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-list,在那里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的评论很好的 CPP 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the list
void show(list<int> &l)
{
    //Defining an iterator for the list
    list<int>::iterator i;

    for (i = l.begin(); i != l.end(); i++)
    {
        cout << "\t" << *i;
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of Lists (Part 2), in CPP  ===== \n\n";

    int i;

    //List declaration (list of integers)
    list<int> l1, l2;

    //Filling the elements
    cout << "Filling the First list from end\n\n";
    for (i = 0; i < 5; i++)
    {
        l1.push_back(i * 5); //inserting elements from end
    }

    cout << "The elements of the First list are: ";
    show(l1);

    //Filling the elements
    cout << "Filling the Second list from front\n\n";
    for (i = 0; i < 5; i++)
    {
        l2.push_front(i * 10); //inserting elements from front
    }

    cout << "The elements of the Second list are: ";
    show(l2);

    cout << "\n\nList 1 after getting reversed is: ";
    l1.reverse();
    show(l1);

    cout << "\n\nList 2 after getting sorted is: ";
    l2.sort();
    show(l2);

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Lists Part 2

我们希望这篇文章能帮助你更好地理解列表的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:** * * *


C++ 程序:STL 偶对模板

原文:https://www.studytonight.com/cpp-programs/cpp-pair-template-in-stl-program

大家好!

在本教程中,我们将学习使用 C++ 编程语言中的向量来处理偶对模板及其实现。

要了解偶对模板的基本功能,我们建议您访问 C++ STL 偶对模板,在这里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of a Pair Template in STL, in CPP  ===== \n\n";

    cout << "\n\nDeclaring a Vector and Filling it with pair of two integers.\n\n";

    //create an empty vector of pair
    vector<pair<int, int>> v;

    //insert elements into the vector
    v.push_back(make_pair(8, 64));
    v.push_back(make_pair(1, 1));
    v.push_back(make_pair(3, 6));
    v.push_back(make_pair(2, 4));
    v.push_back(make_pair(5, 25));

    //prining the vector of pairs
    cout << "Printing the Vector of Pairs: \n";

    int n = v.size();

    //Printing the vector
    for (int i = 0; i < n; i++)
    {
        cout << "\nSquare of " << v[i].first << " is " << v[i].second; //accessing the pair elements
    }

    //Sorting the vector in ascending order - by default on the basis of first element of the pair
    sort(v.begin(), v.end());

    cout << "\n\n\n\nThe elements of the Vector after Sorting are:\n ";

    //prining the Sorted vector
    for (int i = 0; i < n; i++)
    {
        cout << "\nSquare of " << v[i].first << " is " << v[i].second; //accessing the pair elements
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ pair template

我们希望这篇文章能帮助您更好地理解偶对模板的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 偶对模板的自定义排序方法

原文:https://www.studytonight.com/cpp-programs/cpp-custom-sort-method-for-stl-pair-template-program

大家好!

在本教程中,我们将学习创建自定义排序方法来排序偶对模板,并使用 C++ 编程语言中的向量来实现它。

要了解偶对模板的基本功能,我们建议您访问, C++ STL 偶对模板,在这里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Returns true if x is smaller than y
bool cmp(pair<int, int> x, pair<int, int> y)
{
    if (x.first != y.first)
        return x.first < y.first; //return the one with smaller first element
    else
        return x.second < y.second; //if first element is equal then return the one with smaller second element
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate Custom Sorting of a Pair Template, in CPP  ===== \n\n";

    cout << "\n\nDeclaring a Vector and Filling it with integers.\n\n";

    //create an empty vector of pair
    vector<pair<int, int>> v;

    //insert elements into the vector
    v.push_back(make_pair(1, 5));
    v.push_back(make_pair(1, 3));
    v.push_back(make_pair(2, 6));
    v.push_back(make_pair(2, 4));
    v.push_back(make_pair(5, 24));

    //prining the vector of pairs
    cout << "Printing the Vector or Pairs: \n";

    int n = v.size();

    //Printing the vector
    for (int i = 0; i < n; i++)
    {
        cout << "\nPair is: " << v[i].first << " and " << v[i].second; //accessing the pair elements
    }

    cout << "\n\n\n--- Calling the Custom Sort Method ---";
    //Sorting the vector in ascending order of the pair
    sort(v.begin(), v.end(), cmp);

    cout << "\n\nThe elements of the Vector after Sorting are:\n ";

    //prining the Sorted vector
    for (int i = 0; i < n; i++)
    {
        cout << "\nPair is: " << v[i].first << " and " << v[i].second; //accessing the pair elements
    }

    cout << "\n\n\n";

    return 0;
}

输出:

C++ pair template sorting

我们希望这篇文章能帮助您更好地理解偶对模板的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用偶对模板查找排序向量中最常出现的前K个元素

原文:https://www.studytonight.com/cpp-programs/c-find-top-k-most-frequent-elements-in-sorted-vector-using-pair-template

大家好!

在本教程中,我们将学习如何在 C++ 编程语言的排序向量、中找到最常见的 k 个元素。

要了解偶对模板的基本功能,我们建议您访问, C++ STL 偶对模板,在这里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

vector<int> topKFrequent(vector<int> &a, int k)
{
    unordered_map<int, int> u;

    int n = a.size();
    int i;

    for (i = 0; i < n; i++)
    {
        u[a[i]]++;
    }

    vector<pair<int, int>> v(u.begin(), u.end());

    sort(v.begin(), v.end(), [](pair<int, int> x, pair<int, int> y) {
        if (x.second == y.second)
            return x.first < y.first;
        else
            return x.second > y.second;
    });

    vector<int> r;
    for (i = 0; i < k; i++)
    {
        r.push_back(v[i].first);
    }

    return r;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the top k most frequent elements in a vector, in CPP  ===== \n\n\n";

    //initializing vector with the following elements
    vector<int> v = {1, 2, 3, 1, 2, 1};

    vector<int> f;

    int k = 2; //to find the 2 most frequent numbers

    int n = v.size();

    cout << "The elements of the given vector is : ";

    for (int i = 0; i < n; i++)
    {
        cout << v[i] << "  ";
    }

    f = topKFrequent(v, k);

    n = f.size();

    cout << "\n\n The top " << k << " most frequent numbers are: ";

    for (int i = 0; i < n; i++)
    {
        cout << f[i] << "    ";
    }

    cout << "\n\n\n";

    return 0;
}

输出:

C++ top k most frequent

我们希望这篇文章能帮助你更好地理解偶对模板的应用概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 栈

原文:https://www.studytonight.com/cpp-programs/cpp-stl-stack-program

大家好!

在本教程中,我们将学习 C++ 编程语言中栈的工作及其实现

为了了解栈的基本功能,我们将推荐您访问栈数据结构,在这里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the stack
void show(stack<int> s)
{
    while (!s.empty())
    {
        cout << "  " << s.top(); //printing the topmost element
        s.pop();                 //removing the topmost element to bring next element at the top
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of Stacks, in CPP  ===== \n\n";

    int i;

    //Stack declaration (stack of integers)
    stack<int> s;

    //Filling the elements by using the push() method.
    cout << "Filling the Stack in LIFO order:"; //LIFO= Last In First Out
    for (i = 1; i <= 5; i++)
    {
        s.push(i * 10); //inserting elements to the top
    }

    cout << "\n\nThe top-most element of the Stack is :  " << s.top();

    cout << "\n\nThe size of the Stack is :  " << s.size();

    cout << "\n\nThe elements of the Stack in LIFO order are: ";
    show(s);

    cout << "\n\nAfter deleting the top-most element from the stack, it becomes: ";
    s.pop();
    show(s);

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Stack Program

我们希望这篇文章能帮助你更好地理解栈的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:查找栈中最大的元素

原文:https://www.studytonight.com/cpp-programs/cpp-find-the-largest-element-of-the-stack-program

大家好!

在本教程中,我们将学习 C++ 编程语言中栈的工作和找到它的最大元素

为了了解栈的基本功能,我们将推荐您访问栈数据结构,在这里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the Maximum element in the stack
void findMax(stack<int> s)
{
    int m = s.top(); //initialization

    int a;

    while (!s.empty())
    {
        a = s.top();

        if (m < a)
            m = a; //Storing the maximum element in m

        s.pop(); //removing the topmost element to bring next element at the top
    }

    cout << "\n\nThe maximum element of the Stack is: " << m << endl;
}

//Function to print the elements of the stack
void show(stack<int> s)
{
    while (!s.empty())
    {
        cout << "  " << s.top(); //printing the topmost element
        s.pop();                 //removing the topmost element to bring next element at the top
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to Find the Maximum element in the Stack, in CPP  ===== \n\n";

    int i;

    //Stack declaration (stack of integers)
    stack<int> s;

    //Filling the elements by using the push() method.
    cout << "Filling the Stack in LIFO order using the push() method:"; //LIFO= Last In First Out

    s.push(4);
    s.push(2);
    s.push(20);
    s.push(12);
    s.push(52);
    s.push(14);

    cout << "\n\nThe elements of the Stack in LIFO order are: ";
    show(s);

    findMax(s); //to find the max element

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Stack Max

我们希望这篇文章能帮助你更好地理解栈的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用栈检查平衡括号字符串

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-check-for-balanced-bracket-string-using-stack

大家好!

在本教程中,我们将学习概念,即使用 C++ 编程语言中的 Stack、来确定括号的输入字符串是否平衡。

为了了解栈的基本功能,我们将推荐您访问栈数据结构,在这里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

// Returns true is the string is balanced
bool isBalanced(string s)
{
    int i;
    char c;
    int n = s.length();

    stack<char> t;

    for (i = 0; i < n; i++)
    {
        c = s.at(i);

        if (t.empty())
        {
            t.push(c);
        }
        else if (t.top() == '(' && c == ')' || t.top() == '{' && c == '}' || t.top() == '[' && c == ']')
        {
            t.pop();
        }
        else
            t.push(c);
    }

    if (t.empty())
        return true;
    else
        return false;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " ===== Program to determine if the entered string is Balanced using Stack, in CPP  ===== \n\n\n";

    //initializing string to be checked for
    string s1 = "{{[[(())]]}}";
    string s2 = "{[(])}";

    bool b1 = isBalanced(s1);
    bool b2 = isBalanced(s2);

    if (b1)
    {
        cout << "The string " << s1 << " is Balanced.\n\n";
    }
    else
    {
        cout << "The string " << s1 << " is not Balanced.\n\n";
    }

    if (b2)
    {
        cout << "The string " << s2 << " is Balanced.\n\n";
    }
    else
    {
        cout << "The string " << s2 << " is not Balanced.\n\n";
    }

    return 0;
}

输出:

C++ balanced string using Stack

我们希望这篇文章能帮助您更好地理解栈的概念及其实现,以检查 CPP 中的平衡括号字符串。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 优先级队列

原文:https://www.studytonight.com/cpp-programs/cpp-stl-priority-queue-program

大家好!

在本教程中,我们将学习 C++ 编程语言中优先级队列的工作方式。

要了解 CPP 中优先级队列的基本功能,我们将推荐您访问 C++ STL 优先级队列,我们已经从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the Priority Queue
void show(priority_queue<int> q)
{
    //Copying the Priority Queue into another to maintain the original Priority Queue
    priority_queue<int> pq = q;

    while (!pq.empty())
    {
        cout << "\t" << pq.top(); //printing the top most element
        pq.pop();                 //deleting the top most element to move to the next
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Implementation of Priority Queue, in CPP  ===== \n\n";

    int i;

    //Declaring a Priority Queue of integers
    //Note: by default the priority queue is Max heap in c++
    priority_queue<int> q;

    //Filling the elements
    cout << "Inserting elements into the Priority Queue\n\n";
    for (i = 1; i < 6; i++)
    {
        q.push(i * 10);
    }

    cout << "The Priority Queue is: ";
    show(q);

    cout << "\n\nThe number of elements in the Priority Queue are : " << q.size();
    ;

    cout << "\n\nThe first element or the element with the highest priority is: " << q.top();
    ;

    cout << "\n\nAfter Deleting the top most element or the highest priority element from the Priority Queue, it becomes: ";
    q.pop();
    show(q);

    cout << "\n\n\n";

    return 0;
} 

输出:

c++ Priority Queue

我们希望这篇文章能帮助您更好地理解优先级队列的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用优先级队列实现最小堆

原文:https://www.studytonight.com/cpp-programs/cpp-implementing-min-heap-using-priority-queue-program

大家好!

在本教程中,我们将学习最小堆的概念,并使用 C++ 编程语言中的优先级队列来实现它。

最小堆数据结构:

堆数据结构始终是一个完整的二叉树,这意味着树的所有级别都被完全填充。在最小堆中,每个节点的子节点都大于它们的父节点。

为了了解 CPP 中优先级队列的基本功能,我们将推荐您访问 C++ STL 优先级队列,在这里我们从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the Min Heap
void show(priority_queue<int, vector<int>, greater<int>> q)
{
    //Copying the Priority Queue into another to maintain the original Priority Queue
    priority_queue<int, vector<int>, greater<int>> mh = q;

    while (!mh.empty())
    {
        cout << "\t" << mh.top(); //printing the top most element
        mh.pop();                 //deleting the top most element to move to the next
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Implementation of Min Heap using a Priority Queue, in CPP  ===== \n\n";

    int i;

    /* Declaring a Priority Queue of integers
    Note: by default the priority queue is Max heap in c++ : priority_queue<int> q
    To create a Min heap, follow the below declaration of the Priority Queue
    */
    priority_queue<int, vector<int>, greater<int>> minHeap;

    //Filling the elements into the Priority Queue
    cout << "=====  Inserting elements into the Priority Queue  ====\n\n";
    for (i = 1; i < 6; i++)
    {
        minHeap.push(i * 20);
    }

    cout << "The number of elements in the Min Heap are : " << minHeap.size();
    ;

    cout << "\n\nThe first element or the element with the highest priority is: " << minHeap.top();
    ;

    cout << "\n\nThe elements of the Min Heap are: ";
    show(minHeap);

    cout << "\n\nAfter Deleting the first or the smallest element from the Min Heap, it becomes: ";
    minHeap.pop();
    show(minHeap);

    cout << "\n\nThe number of elements in the Min Heap after deleting the smallest element are : " << minHeap.size();
    ;

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Min Heap

我们希望这篇文章能帮助你更好地理解最小堆的概念,以及它在 C++ 中使用优先级队列的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 集合(第一部分)

原文:https://www.studytonight.com/cpp-programs/cpp-stl-sets-program-part-1

大家好!

在本教程中,我们将学习 C++ 编程语言中集合的工作及其实现

什么是集合?

在编程中,集合用于存储列表的唯一值,并自动为其元素提供排序。默认情况下,顺序是升序。

使用insert()方法插入元素。如果同一个值被插入多次,集合会自动删除重复项,并且只存储该元素的单个副本。

使用erase()方法删除集合的元素。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the set using an iterator
void show(set<int> s)
{
    //declaring an iterator to iterate through the set
    set<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the set using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of Sets (Part 1), in CPP  ===== \n\n\n\n";

    cout << " ***  Set automatically removes the duplicate elements and also sorts the input in ascending order *** \n\n";

    //Set declaration (Set of integers)
    set<int> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Set with integers in random order."; //Set automatically stores them in order

    s.insert(5);
    s.insert(39);
    s.insert(64);
    s.insert(82);
    s.insert(35);
    s.insert(54);

    cout << "\n\nThe elements of the Set are: ";
    show(s);

    cout << "\n\nAfter deleting the element 54 from the set using the erase() method, it becomes: ";
    s.erase(54);
    show(s);

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Set Part 1

我们希望这篇文章能帮助你更好地理解 Set 的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 集合(第二部分)

原文:https://www.studytonight.com/cpp-programs/cpp-stl-sets-program-part-2

大家好!

在本教程中,我们将学习 C++ 编程语言中集合的工作及其实现。我们还将讨论如何以降序存储元素,以及如何在不使用迭代器的情况下将一个集合的元素复制到另一个集合中。

什么是集合?

在编程中,集合用于存储列表的唯一值,并自动为其元素提供排序。默认情况下,顺序是升序。

使用insert()方法插入元素。如果同一个值被插入多次,集合会自动删除重复项,并且只存储该元素的单个副本。

使用erase()方法删除集合的元素。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the set using an iterator
void show(set<int, greater<int>> s)
{
    //declaring an iterator to iterate through the set
    set<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the set using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of Sets (Part 2), in CPP  ===== \n\n\n\n";

    cout << " ***  Set automatically removes the duplicate elements and also sorts the input in ascending order (by default) *** \n\n";

    /* Set declaration (Set of integers)
        Note: By default, the declaration set<int> s stores the elements in ascending order
        But the below declaration stores them in decreasing order
    */
    set<int, greater<int>> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Set with integers in random order."; //Set automatically stores them in order

    s.insert(5);
    s.insert(39);
    s.insert(64);
    s.insert(64); //as 64 is added twice, but it will be stored only once in the set
    s.insert(82);
    s.insert(35);
    s.insert(54);

    cout << "\n\nThe number of elements in the Set are: " << s.size();

    cout << "\n\nThe elements of the Set s are: ";
    show(s);

    //Creating and initializing the set s2 with the elements of the set s
    set<int, greater<int>> s2(s.begin(), s.end());

    cout << "\n\nAfter copying the elements of the Set s into s2, the set s2 is : ";
    show(s2);

    cout << "\n\nThe number of elements in the Set s2 before using the erase() method are: " << s2.size();

    cout << "\n\nAfter deleting the element 35 from the Set s2 using the erase() method, it becomes: ";
    s2.erase(35);
    show(s2);

    cout << "\n\nThe number of elements in the Set s2 after using the erase() method are: " << s2.size();

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Set Part 2

我们希望这篇文章能帮助你更好地理解 Set 的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 集合find()方法

原文:https://www.studytonight.com/cpp-programs/cpp-working-of-stl-set-find-method-program

大家好!

在本教程中,我们将学习 STL 中 find() 方法的工作原理,以及使用 C++ 编程语言中的 Set** 实现**

什么是集合?

在编程中,集合用于存储列表的唯一值,并自动为其元素提供排序。默认情况下,顺序是升序。

使用insert()方法插入元素。如果同一个值被插入多次,集合会自动删除重复项,并且只存储该元素的单个副本。

使用erase()方法删除集合的元素。

find(x)方法返回一个迭代器到集合容器中搜索到的元素(这里是x)。如果没有找到该元素,则迭代器指向集合中最后一个元素之后的位置。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the set using an iterator
void show(set<int> s)
{
    //declaring an iterator to iterate through the set
    set<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the set using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of find() method of STL, in CPP  ===== \n\n\n\n";

    cout << " ***  find(x) methods returns a pointer to the element x if present, and pointer to end element if not present.  *** \n\n";

    //Set declaration (Set of integers)
    set<int> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Set with integers in random order."; //Set automatically stores them in order

    s.insert(5);
    s.insert(39);
    s.insert(64);
    s.insert(82);
    s.insert(35);
    s.insert(54);

    cout << "\n\nThe elements of the Set are: ";
    show(s);

    set<int>::iterator it;

    //An iterator pointing to the element 39
    it = s.find(39);

    cout << "\n\nPrinting the elements of the Set that are greater than or equal to 39 : ";

    for (; it != s.end(); it++)
    {
        cout << " " << *it;
    }

    cout << "\n\nAfter deleting the element 39 from the set using the erase() method, it becomes: ";
    s.erase(39);
    show(s);

    //An iterator pointing to the element 39
    it = s.find(39);

    if (it == s.end())
        cout << "\n\nElement 39 is not present in the Set.";

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ find() method in set

我们希望这篇文章能帮助你更好地理解 Set 中 find()方法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 集合erase()方法

原文:https://www.studytonight.com/cpp-programs/cpp-working-of-stl-set-erase-method-program

大家好!

在本教程中,我们将学习 C++ 编程语言中多重集合的工作及其实现

什么是集合?

在编程中,集合用于存储列表的唯一值,并自动为其元素提供排序。默认情况下,顺序是升序。

使用insert() 方法插入元素。如果同一个值被插入多次,集合会自动删除重复项,并且只存储该元素的单个副本。

使用erase()方法删除集合的元素。

erase(s.begin(),s.find(x))方法从开始到小于x删除集合的所有元素。

什么是多重集合?

多重集合类似于集合,除了多个元素可以有相同的值(重复的被保留)。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the multiset using an iterator
void show(multiset<int> s)
{
    //declaring an iterator to iterate through the multiset
    multiset<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the multiset using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of a Multiset, in CPP  ===== \n\n\n\n";

    cout << "*** Multisets are similar to set, with an exception that multiple elements can have same values. *** \n\n";

    //Set declaration (Set of integers)
    multiset<int> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Multiset with integers in random order."; //Multiset automatically stores them in order

    s.insert(5);
    s.insert(39);
    s.insert(5);
    s.insert(82);
    s.insert(39);
    s.insert(54);

    cout << "\n\nThe number of elements in the Multiset are: " << s.size();

    cout << "\n\nThe elements of the Multiset are: ";
    show(s);

    multiset<int>::iterator it;

    //Deleting all the elements of the set that are less than 54
    s.erase(s.begin(), s.find(54));

    cout << "\n\nAfter deleting all the elements that are less than 54, the Multiset becomes : ";

    for (it = s.begin(); it != s.end(); it++)
    {
        cout << " " << *it;
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ multiset

我们希望这篇文章能帮助你更好地理解多重集合的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 多重集合

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-multiset-program

大家好!

在本教程中,我们将学习 STL 中多重集合的工作方式及其在 C++ 编程语言中的实现

什么是集合?

在编程中,集合用于存储列表的唯一值,并自动为其元素提供排序。默认情况下,排序为升序。

使用insert()方法插入元素。如果同一个值被插入多次,集合会自动删除重复项,并且只存储该元素的单个副本。

使用erase() 方法删除集合的元素。

erase(s.begin(),s.find(x))方法从开始到小于 x 删除集合的所有元素。

什么是多重集合?

多重集合类似于集合,除了多个元素可以有相同的值(重复的被保留)。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the multiset using an iterator
void show(multiset<int> s)
{
    //declaring an iterator to iterate through the multiset
    multiset<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the multiset using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of a Multiset, in CPP  ===== \n\n\n\n";

    cout << "*** Multisets are similar to set, with an exception that multiple elements can have same values. *** \n\n";

    //Set declaration (Set of integers)
    multiset<int> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Multiset with integers in random order."; //Multiset automatically stores them in order

    s.insert(5);
    s.insert(39);
    s.insert(5);
    s.insert(82);
    s.insert(39);
    s.insert(54);

    cout << "\n\nThe number of elements in the Multiset are: " << s.size();

    cout << "\n\nThe elements of the Multiset are: ";
    show(s);

    multiset<int>::iterator it;

    //Deleting all the elements of the set that are less than 54
    s.erase(s.begin(), s.find(54));

    cout << "\n\nAfter deleting all the elements that are less than 54, the Multiset becomes : ";

    for (it = s.begin(); it != s.end(); it++)
    {
        cout << " " << *it;
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ multiset

我们希望这篇文章能帮助你更好地理解 STL 中多重集合的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 映射

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-map-program

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL 中 Map 的概念。

要了解 STL 中映射容器的基本功能,我们将推荐您访问 C++ STL 映射,我们已经从头开始详细解释了这个概念。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of a Ordered Map, in CPP  ===== \n\n\n\n";

    cout << "*** Each Element of a Map is a key value par. *** \n\n";

    //Map declaration (Map with key and value both as integers)
    map<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Map with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 9));
    m.insert(make_pair(2, 4));
    m.insert(make_pair(5, 25));
    m.insert(make_pair(9, 81));
    m.insert(make_pair(1, 1));

    cout << "\n\nThe number of elements in the Map are: " << m.size();

    cout << "\n\nThe elements of the Map m are: ";

    map<int, int>::iterator i;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "\nSquare of " << i->first << " is " << i->second;
    }

    //Initializing a map with the elements of another map

    map<int, int> m1(m.begin(), m.end());

    //Printing the copied map
    cout << "\n\nThe elements of the Map m1 are: ";

    for (i = m1.begin(); i != m1.end(); i++)
    {
        cout << "\nSquare of " << i->first << " is " << i->second;
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Using Map program

我们希望这篇文章能帮助你更好地理解 STL 中映射容器的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 映射中使用find()方法

原文:https://www.studytonight.com/cpp-programs/cpp-using-find-method-in-stl-map-program

大家好!

在本教程中,我们将在 C++ 编程语言的映射中了解 find() 方法的工作方式。****

要了解 STL 中映射容器的基本功能,我们将推荐您访问 C++ STL 映射容器,我们已经从头开始详细解释了这个概念。

find(x)方法返回一个迭代器给键为x的对,如果没有找到则指向end()

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of find() method in a Map, in CPP  ===== \n\n\n";

    cout << "*** The find(x) method returns an iterator to the pair with key as x and points to end() if not found. *** \n\n";

    //Map declaration (Map with key and value both as integers)
    map<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Map with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 9));
    m.insert(make_pair(2, 4));
    m.insert(make_pair(5, 25));
    m.insert(make_pair(9, 81));
    m.insert(make_pair(1, 1));

    cout << "\n\nThe number of elements in the Map are: " << m.size();

    cout << "\n\nThe elements of the Map m are: ";

    map<int, int>::iterator i;
    int j = 0;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "\n The Key " << ++j << " of Map m is " << i->first << " and it's corresponding value is " << i->second;
    }

    //Finding the map element with key 5

    i = m.find(5);

    if (i != m.end())
    {
        cout << "\n\nThe Map element with key 5 is " << i->second;
    }

    else
    {
        cout << "\n\nThe Map element with key 5 does not exist.";
    }

    i = m.find(6);

    if (i != m.end())
    {
        cout << "\n\nThe Map element with key 6 is " << i->second;
    }

    else
    {
        cout << "\n\nThe Map element with key 6 does not exist.";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ find() map

我们希望这篇文章能帮助您更好地理解 Map 中 find()方法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 映射中使用erase()方法(第一部分)

原文:https://www.studytonight.com/cpp-programs/cpp-using-erase-method-in-a-stl-map-part-1

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL 中的 Map 中 erase()方法的工作方式。

要了解 STL 中映射容器的基本功能,我们将推荐您访问 C++ STL 映射容器,我们已经从头开始详细解释了这个概念。

在映射中,erase(x)方法删除所有带有键x的元素。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of erase() method in a Map (Part 1), in CPP  ===== \n\n\n";

    cout << "*** The erase(x) method deletes the map element with key as x and returns 1 if found else returns 0\. *** \n\n";

    //Map declaration (Map with key and value both as integers)
    map<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Map with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 9));
    m.insert(make_pair(2, 4));
    m.insert(make_pair(5, 25));
    m.insert(make_pair(9, 81));
    m.insert(make_pair(1, 1));

    cout << "\n\nThe number of elements in the Map are: " << m.size();

    cout << "\n\nThe elements of the Map m are: ";

    map<int, int>::iterator i;
    int j = 0;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    //Finding the map element with key 5

    j = m.erase(5);

    if (j == 1)
    {
        cout << "\n\nThe Map element with key 5 is deleted.";
    }

    else
    {
        cout << "\n\nThe Map element with key 5 does not exist.";
    }

    cout << "\n\nThe number of elements in the Map becomes: " << m.size();

    cout << "\n\nThe elements of the Map m after the erase operation are:  ";

    j = 0;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    j = m.erase(6);

    if (i != m.end())
    {
        cout << "\n\nThe Map element with key 6 is deleted\n\n";
    }

    else
    {
        cout << "\n\nThe Map element with key 6 does not exist.";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ erase() Map

我们希望这篇文章能帮助你更好地理解 STL 中映射容器中erase()方法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 映射中使用erase()方法(第二部分)

原文:https://www.studytonight.com/cpp-programs/cpp-using-erase-method-in-stl-map-part-2

大家好!

在本教程中,我们将学习 erase() 方法的工作原理,在 C++ 编程语言的 STL** 中删除映射中的一系列元素。**

要了解 STL 中映射容器的基本功能,我们将推荐您访问 C++ STL 映射容器,我们已经从头开始详细解释了这个概念。

在映射中,erase(m.begin(), m.find(x))方法删除所有键小于键x的元素。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of erase() method in a Map (Part 2), in CPP  ===== \n\n\n";

    cout << "*** The erase(m.begin(),m.find(x)) method deletes the map element with key less than x. *** \n\n";

    //Map declaration (Map with key and value both as integers)
    map<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Map with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 30));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(5, 50));
    m.insert(make_pair(9, 90));
    m.insert(make_pair(1, 10));

    cout << "\n\nThe number of elements in the Map are: " << m.size();

    cout << "\n\nThe elements of the Map m are: ";

    map<int, int>::iterator i;
    int j = 0;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    //Deleting the map elements with key less than 3
    m.erase(m.begin(), m.find(3));

    cout << "\n\nThe number of elements in the Map becomes: " << m.size();

    cout << "\n\nThe elements of the Map m after the erase operation are:  ";

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ erase() Map part 2

我们希望这篇文章能帮助你更好地理解erase()方法的概念,该方法在 STL 中删除映射容器中的一系列元素,并在 C++ 中实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:通过编写自定义排序方法来排序字符串

原文:https://www.studytonight.com/cpp-programs/cpp-sorting-strings-by-writing-a-custom-sort-method

大家好!

在本教程中,我们将学习如何使用 C++ 编程语言中的自定义排序方法及其实现根据长度对字符串进行排序。

什么是集合?

在编程中,集合用于存储列表的唯一值,并自动为其元素提供排序。默认情况下,顺序是升序。

使用insert()方法插入元素。如果同一个值被插入多次,集合会自动删除重复项,并且只存储该元素的单个副本。

使用erase()方法删除集合的元素。

什么是无序集?

无序集还通过删除重复项来仅存储元素的单个副本,但不会像集中那样自动对元素进行排序。

无序集在内部使用哈希表,因此排序是随机的,取决于内部使用的哈希函数。

自定义排序方法:

每当我们需要明确确定排序的条件时,我们需要创建这个方法来定义逻辑。

为了更好地理解它的实现,请参考下面给出的评论很好的 CPP 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Returns true if first string is of longer length than second
bool cmp(string x, string y)
{
    int n = x.length();
    int m = y.length();

    if (n > m)
        return true;
    else
        return false;
}

//Function to print the elements of the unordered set using an iterator
void show(unordered_set<string> s)
{
    //declaring an iterator to iterate through the unordered set
    unordered_set<string>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "     "; //accessing the elements of the unordered set using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Sorting Strings on the basis of length, in CPP  ===== \n\n\n\n";

    cout << " *** Unordered Set automatically removes the duplicate elements and maintains a random ordering. *** \n\n";

    cout << " *** This random ordering depends on the hash function that is used internally. *** \n\n";

    cout << " *** Unordered set can be sorted by copying its elements to a Vector. *** \n\n";

    //Unordered Set declaration (Unordered Set of strings)
    unordered_set<string> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Unordered Set with strings in random order."; //Unlike Set, this is not automatically sorted

    s.insert("Study");
    s.insert("Tonight");
    s.insert("Aditya");
    s.insert("Abhishek");
    s.insert("C++");
    s.insert("Hi");

    cout << "\n\nThe elements of the Unordered Set before sorting are:\n ";
    show(s);

    //Declaring a vector and initializing it with the elements of the unordered set
    vector<string> v(s.begin(), s.end());

    //Sorting the vector elements in descending order of their length using a custom comparator
    sort(v.begin(), v.end(), cmp);

    cout << "\n\nThe elements of the Unordered Set after sorting in descending Order of their length using a custom comparator are: \n";

    //declaring an iterator to iterate through the vector
    vector<string>::iterator it;

    for (it = v.begin(); it != v.end(); it++)
    {
        cout << *it << "     "; //accessing the elements of the vector using * as i stores the address to each element
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Custom Sort in Unordered Set

我们希望这篇文章能帮助你更好地理解编写自定义排序方法来排序无序集的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 映射中使用lower_bound()upper_bound()方法

原文:https://www.studytonight.com/cpp-programs/cpp-using-lower_bound-and-upper_bound-methods-in-map-in-stl

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL 中 Map 的下界()和上界()方法的工作方式。

要了解 STL 中映射容器的基本功能,我们将推荐您访问 STL 映射容器,我们从零开始详细解释了这个概念。

lower_bound()方法:

**lower_bound()**方法返回一个指向第一个元素的迭代器,该元素的值不小于给定值

upper_bound()方法:

**upper_bound()**方法是一个迭代器,指向第一个元素,该元素的值大于给定值

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the lower_bound() and upper_bound() in Map, in CPP  ===== \n\n\n";

    //Map declaration (Map with key and value both as integers)
    map<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "Filling the Map with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 30));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(5, 50));
    m.insert(make_pair(9, 90));
    m.insert(make_pair(1, 10));

    cout << "\n\nThe number of elements in the Map are: " << m.size();

    cout << "\n\nThe elements of the Map m are: ";

    map<int, int>::iterator i;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    map<int, int>::iterator low, high;

    //lower_bound(x) returns the iterator to the first element that is greater than or equal to element with key x
    low = m.lower_bound(5);

    cout << "\n\nThe lower bound of 5 has key: " << low->first << " and value: " << low->second << ". ";

    low = m.lower_bound(6);

    cout << "\n\nThe lower bound of 6 has key: " << low->first << " and value: " << low->second << ". ";

    //upper_bound(x) returns the iterator to the first element that is greater than element with key x
    high = m.upper_bound(3);

    cout << "\n\nThe upper bound of 3 has key: " << high->first << " and value: " << high->second << ". ";

    high = m.upper_bound(4);

    cout << "\n\nThe upper bound of 4 has key: " << high->first << " and value: " << high->second << ". ";

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ erase() Map

我们希望这篇文章能帮助您更好地理解 STL 中映射容器的下界()和上界()方法的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 多重映射

原文:https://www.studytonight.com/cpp-programs/cpp-stl-multimap-program

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL 中多重映射的概念。

要了解 STL 中映射容器的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-map,我们已经从头开始详细解释了这个概念。

什么是多重映射?

多重映射类似于映射,具有两个附加功能:

  1. 多个元素可以有相同或重复的键。

  2. 多个元素可以有相同或重复的键值对。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Multimap (Part 1), in CPP  ===== \n\n\n";

    cout << " Multimap is similar to map with two additional functionalities: \n1\. Multiple elements can have same keys or \n2\. Multiple elements can have same key-value pair.\n\n";

    //Multimap declaration (Multimap with key and value both as integers)
    multimap<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "Filling the Multimap with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 30));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(5, 50));
    m.insert(make_pair(9, 90));
    m.insert(make_pair(1, 10));
    m.insert(make_pair(3, 30));
    m.insert(make_pair(3, 60));

    cout << "\n\nThe number of elements in the Multimap are: " << m.size();

    cout << "\n\nThe elements of the Multimap m are: ";

    multimap<int, int>::iterator i;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    //Copying one multimap into another
    multimap<int, int> m1(m.begin(), m.end());

    cout << "\n\nThe elements of the Multimap m1 are: ";

    for (i = m1.begin(); i != m1.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Multimap program example

我们希望这篇文章能帮助你更好地理解 STL 中多重映射容器的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 多重映射中使用find()方法

原文:https://www.studytonight.com/cpp-programs/cpp-using-find-method-in-a-stl-multimap

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL 中的 Map 中 erase()方法的工作方式。

要了解 STL 中映射容器的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-map,我们已经从头开始详细解释了这个概念。

什么是 Multimap?

多重映射类似于映射,具有两个附加功能:

  1. 多个元素可以有相同或重复的键。

  2. 多个元素可以有相同或重复的键值对。

在多重映射中,find(x)方法用键x返回第一个元素的迭代器。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept find() method in Multimap, in CPP  ===== \n\n\n";

    cout << " In Multimap, find(x) returns an iterator to the very first elements with key x.\n\n";

    //Multimap declaration (Multimap with key and value both as integers)
    multimap<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "Filling the Multimap with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 30));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(5, 50));
    m.insert(make_pair(9, 90));
    m.insert(make_pair(1, 10));
    m.insert(make_pair(3, 60));

    cout << "\n\nThe number of elements in the Multimap are: " << m.size();

    cout << "\n\nThe elements of the Multimap m are: ";

    multimap<int, int>::iterator i;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    //Copying one multimap into another
    multimap<int, int> m1(m.begin(), m.end());

    multimap<int, int>::iterator f;

    //Finding the very first element with key as 3
    f = m1.find(3);

    cout << "\n\nThe m1.find(3) method returns an iterator to the element: ( " << f->first << ", " << f->second << " ) ";

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ find() MultiMap program

我们希望这篇文章能帮助你更好地理解 STL 中映射容器中find()方法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 多重映射中使用erase()方法(第一部分)

原文:https://www.studytonight.com/cpp-programs/cpp-using-erase-method-in-a-stl-multimap-part-1

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL(第一部分)中的 Map 中 erase()方法的工作方式。

要了解 STL 中映射容器的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-map,我们已经从头开始详细解释了这个概念。

什么是 Multimap?

多重映射类似于映射,具有两个附加功能:

  1. 多个元素可以有相同或重复的键。

  2. 多个元素可以有相同或重复的键值对。

在多重映射中,erase(x)用键x删除所有元素。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept erase() method in Multimap, in CPP  ===== \n\n\n";

    cout << " In Multimap, erase(x) deletes all the elements with key x.\n\n";

    //Multimap declaration (Multimap with key and value both as integers)
    multimap<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "Filling the Map with key-value pairs of integers in random order."; //Map automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the map
    m.insert(make_pair(3, 30));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(5, 50));
    m.insert(make_pair(9, 90));
    m.insert(make_pair(1, 10));
    m.insert(make_pair(3, 30));
    m.insert(make_pair(3, 60));

    cout << "\n\nThe number of elements in the Multimap are: " << m.size();

    cout << "\n\nThe elements of the Multimap m are: ";

    multimap<int, int>::iterator i;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    //Copying one multimap into another
    multimap<int, int> m1(m.begin(), m.end());

    //Deleting all the elements with key as 3
    m1.erase(3);

    cout << "\n\nThe elements of the Multimap m1 after deleting all the elements with key as 3 using m1.erase(3), are:\n ";

    for (i = m1.begin(); i != m1.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ erase() Multimap 1

我们希望这篇文章能帮助你更好地理解 STL 中多重映射容器中erase()方法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 STL 多重映射中使用erase()方法(第二部分)

原文:https://www.studytonight.com/cpp-programs/cpp-using-erase-method-in-stl-multimap-part-2

大家好!

在本教程中,我们将学习在 C++ 编程语言的 STL(第 2 部分)中的映射中使用方法。

要了解 STL 中映射容器的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-map,我们已经从头开始详细解释了这个概念。

什么是 Multimap?

多重映射类似于映射,具有两个附加功能:

  1. 多个元素可以有相同或重复的键。

  2. 多个元素可以有相同或重复的键值对。

在多重映射中,erase(m.begin(), m.find(x))删除所有键小于键x的元素。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept erase() method in Multimap (Part 2), in CPP  ===== \n\n\n";

    cout << " In Multimap, erase(m.begin(), m.find(x)) deletes all the elements with key smaller than key x.\n\n";

    //Multimap declaration (Multimap with key and value both as integers)
    multimap<int, int> m;

    //Filling the elements by using the insert() method.
    cout << "Filling the Multimap with key-value pairs of integers in random order."; //Multimap automatically stores them in increasing order of keys

    //make_pair() is used to insert a key value pair into the Multimap
    m.insert(make_pair(3, 30));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(5, 50));
    m.insert(make_pair(9, 90));
    m.insert(make_pair(1, 10));
    m.insert(make_pair(6, 50));
    m.insert(make_pair(3, 60));

    cout << "\n\nThe number of elements in the Multimap are: " << m.size();

    cout << "\n\nThe elements of the Multimap m are: ";

    multimap<int, int>::iterator i;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    //Copying one multimap into another
    multimap<int, int> m1(m.begin(), m.end());

    //Deleting all the elements with key smaller than 5
    m1.erase(m1.begin(), m1.find(5));

    cout << "\n\nThe elements of the Multimap m1 after deleting all the elements with key smaller than as 5 are:\n ";

    for (i = m1.begin(); i != m1.end(); i++)
    {
        cout << "( " << i->first << ", " << i->second << " ) ";
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ erase() Multimap 2

我们希望这篇文章能帮助你更好地理解 STL 中多重映射容器中erase()方法的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:STL 无序集

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-unordered-set-program

大家好!

在本教程中,我们将学习 C++ 编程语言中无序集的工作及其实现

什么是集合?

在编程中,集合用于存储列表的唯一值,并自动为其元素提供排序。默认情况下,顺序是升序。

使用insert()方法插入元素。如果同一个值被插入多次,集合会自动删除重复项,并且只存储该元素的单个副本。

使用erase()方法删除集合的元素。

什么是无序集?

无序集还通过删除重复项来仅存储元素的单个副本,但不会像集中那样自动对元素进行排序。

无序集在内部使用哈希表,因此排序是随机的,取决于内部使用的哈希函数。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the unordered set using an iterator
void show(unordered_set<int> s)
{
    //declaring an iterator to iterate through the unordered set
    unordered_set<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the unordered set using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of Unordered Sets (Part 1), in CPP  ===== \n\n\n\n";

    cout << " *** Unordered Set automatically removes the duplicate elements and maintains a random ordering. *** \n\n";

    cout << " *** This random ordering depends on the hash function that is used internally. *** \n\n";

    //Unordered Set declaration (Unordered Set of integers)
    unordered_set<int> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Unordered Set with integers in random order."; //Unlike Set, this is not automatically sorted

    s.insert(5);
    s.insert(39);
    s.insert(64);
    s.insert(82);
    s.insert(35);
    s.insert(54);

    cout << "\n\nThe elements of the Unordered Set are: ";
    show(s);

    cout << "\n\nAfter deleting the element 39 from the unordered set using the erase() method, it becomes: ";
    s.erase(39);
    show(s);

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Unordered Set Program

我们希望这篇文章能帮助你更好地理解无序集的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:排序 STL 中的无序集

原文:https://www.studytonight.com/cpp-programs/cpp-program-to-sort-an-unordered-set-in-stl

大家好!

在本教程中,我们将学习 C++ 编程语言中无序集的工作及其实现

什么是无序集?

无序集还通过删除重复项来仅存储元素的单个副本,但不会像集中那样自动对元素进行排序。

无序集在内部使用哈希表,因此排序是随机的,取决于内部使用的哈希函数。

对无序集进行排序:

无序集可以通过将其元素复制到向量中,然后使用 STL 的sort()方法进行排序。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

bool cmp(int x, int y)
{
    if (x > y)
        return true;
    else
        return false;
}

//Function to print the elements of the unordered set using an iterator
void show(unordered_set<int> s)
{
    //declaring an iterator to iterate through the unordered set
    unordered_set<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the unordered set using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Sorting of an Unordered Set, in CPP  ===== \n\n\n\n";

    cout << " *** Unordered Set automatically removes the duplicate elements and maintains a random ordering. *** \n\n";

    cout << " *** This random ordering depends on the hash function that is used internally. *** \n\n";

    cout << " *** Unordered set can be sorted by copying its elements to a Vector. *** \n\n";

    //Unordered Set declaration (Unordered Set of integers)
    unordered_set<int> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Unordered Set with integers in random order."; //Unlike Set, this is not automatically sorted

    s.insert(5);
    s.insert(39);
    s.insert(64);
    s.insert(82);
    s.insert(35);
    s.insert(54);

    cout << "\n\nThe elements of the Unordered Set before sorting are: ";
    show(s);

    //Declaring a vector and initializing it with the elements of the unordered set
    vector<int> v(s.begin(), s.end());

    //Sorting the vector elements in descending order using a custom comparator
    sort(v.begin(), v.end(), cmp);

    cout << "\n\nThe elements of the Unordered Set after sorting in descending Order using a Custom sort method are: \n";

    //declaring an iterator to iterate through the unordered set
    vector<int>::iterator it;

    for (it = v.begin(); it != v.end(); it++)
    {
        cout << *it << "  "; //accessing the elements of the vector using * as i stores the address to each element
    }

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ sorting an Unordered Set

我们希望这篇文章能帮助你更好地理解排序无序集的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 无序多重集合

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-unordered-multiset-program

大家好!

在本教程中,我们将学习 STL 中多重集合的工作方式及其在 C++ 编程语言中的实现

什么是多重集合?

多重集合类似于集合,除了多个元素可以有相同的值(重复的被保留)。

什么是无序多重集合?

它与多重集合相同,但这里的元素不是排序的,而是随机存储的。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Function to print the elements of the vector using an iterator
void showVector(vector<int> v)
{
    //declaring an iterator to iterate through the vector elements
    vector<int>::iterator i;

    for (i = v.begin(); i != v.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the vector using * as i stores the address to each element
    }

    cout << endl;
}

//Function to print the elements of the unordered multiset using an iterator
void showMultiset(unordered_multiset<int> s)
{
    //declaring an iterator to iterate through the multiset
    unordered_multiset<int>::iterator i;

    for (i = s.begin(); i != s.end(); i++)
    {
        cout << *i << "  "; //accessing the elements of the unordered multiset using * as i stores the address to each element
    }

    cout << endl;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of a Unordered Multiset, in CPP  ===== \n\n\n\n";

    cout << "*** Multisets are similar to set, with an exception that multiple elements can have same values. *** \n\n";

    cout << "*** Unordered Multisets stores its elements in a random order depending on the hash method used internally. *** \n\n";

    //Unordered Multiset declaration (Set of integers where duplicates are allowed)
    unordered_multiset<int> s;

    //Filling the elements by using the insert() method.
    cout << "\n\nFilling the Multiset with integers in random order."; //Unordered Multiset stores them in a random order

    s.insert(50);
    s.insert(30);
    s.insert(50);
    s.insert(80);
    s.insert(30);
    s.insert(60);

    cout << "\n\nThe number of elements in the Unordered Multiset are: " << s.size();

    cout << "\n\nThe elements of the Unordered Multiset are: ";
    showMultiset(s);

    //Sorting the unordered multiset by copying its elements to a vector
    vector<int> v(s.begin(), s.end());

    vector<int>::iterator it;

    cout << "\n\nThe elements of the Unordered Multiset after sorting using a vector are: ";

    //sorting the vector elements in ascending order
    sort(v.begin(), v.end());

    showVector(v);

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ unordered multiset

我们希望这篇文章能帮助你更好地理解 STL 中无序多重集合的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 无序映射

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-unordered-map-program

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL 中无序映射的概念。

要了解 STL 中映射容器的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-map,在这里我们从头开始详细解释了这个概念。

什么是无序映射?

它与映射相同,只是它不按键的排序顺序存储键值对,而是按随机顺序存储它们。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";

    cout << " =====  Program to demonstrate the working of an Unordered Map, in CPP  ===== \n\n";

    cout << "*** Each Element of a Map is a key value pair. *** \n\n";

    cout << "*** When two elements having same key are inserted then only the latest copy is stored. *** \n\n";

    cout << "***  An Unordered map internally uses a Hash Table to store the keys. *** \n\n";

    //Unordered Map declaration (Map with key as integer and value as string)
    unordered_map<int, string> m;

    //Filling the elements by using the m[key]=value format.
    cout << "\n\nFilling the Map with key-value pairs using the map[key]=value syntax."; //Unordered Map stores this in a random order

    m[3] = "Three";
    m[4] = "Four";
    m[1] = "One";
    m[20] = "Twenty";
    m[31] = "Thirty One";
    m[3] = "Four";

    cout << "\n\nThe number of elements in the Unordered Map are: " << m.size();

    cout << "\n\nThe elements of the Unordered Map stored using the Hash Table are: \n\n";

    unordered_map<int, string>::iterator i;

    int j = 0;

    for (i = m.begin(); i != m.end(); i++)
    {
        cout << "\n   Key number " << ++j << " is: " << i->first << " and its values is: " << i->second;
    }

    cout << "\n\nNote that only the latest copy with key 3 is stored with value four.";

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ Unordered Map program example

我们希望这篇文章能帮助你更好地理解 STL 中无序映射容器的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:使用 STL 无序多重映射

原文:https://www.studytonight.com/cpp-programs/cpp-using-stl-unordered-multimap-program

大家好!

在本教程中,我们将学习 C++ 编程语言中 STL 中多重映射的概念。

要了解 STL 中映射容器的基本功能,我们将推荐您访问https://www.studytonight.com/cpp/stl/stl-container-map,我们已经从头开始详细解释了这个概念。

什么是 Multimap?

多重映射类似于映射,具有两个附加功能:

  1. 多个元素可以有相同或重复的键。

  2. 多个元素可以有相同或重复的键值对。

什么是无序多重映射?

它与多重映射相同,只是它以随机顺序存储键值对,而不像多重映射那样以键的排序顺序存储元素。

为了更好地理解它的实现,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

void showMultimap(unordered_multimap<int, string> mm)
{
    unordered_multimap<int, string>::iterator i;
    int j = 0;

    for (i = mm.begin(); i != mm.end(); i++)
    {
        cout << " Pair #" << ++j << ":( " << i->first << ", " << i->second << " )\n";
    }
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Unordered Multimap, in CPP  ===== \n\n\n";

    cout << " Multimap is similar to map with two additional functionalities: \n1\. Multiple elements can have same keys or \n2\. Multiple elements can have same key-value pair.\n\n";

    cout << "**** Unordered Multimap internally uses a Hash table to order the elements. ****\n\n";

    //Unordered Multimap declaration (Unordered Multimap with key as integer and value as string)
    unordered_multimap<int, string> m;

    //Filling the elements by using the insert() method.
    cout << "Filling the Unordered Multimap with key-value pairs in random order."; //Unordered Multimap stores them in random order

    //make_pair() is used to insert a key value pair into the multimap: similar to map[key]=value format
    m.insert(make_pair(3, "Three"));
    m.insert(make_pair(20, "Twenty"));
    m.insert(make_pair(5, "five"));
    m.insert(make_pair(9, "ninety"));
    m.insert(make_pair(1, "one"));
    m.insert(make_pair(3, "three")); //duplicate key with different value
    m.insert(make_pair(3, "Three")); //the duplicate key-value pair

    cout << "\n\nThe number of elements in the Unordered Multimap are: " << m.size();

    cout << "\n\nThe elements of the Unordered Multimap m are:\n\n";
    showMultimap(m);

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ unordered Multimap

我们希望这篇文章能帮助你更好地理解 STL 中无序多重映射容器的概念及其在 CPP 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



杂项

C++ 程序:查找n个用户输入数字的平均值

原文:https://www.studytonight.com/cpp-programs/cpp-program-find-average-of-n-user-input-numbers

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中,在不使用数组的情况下,对用户输入的 n 个数字进行平均。

从这段代码中学到的一件事是,当我们不必使用用户输入的单个元素时,没有必要创建和数组或任何这样的数据结构来存储它们,因为这只会导致空间浪费。

下面给出的注释代码将帮助您详细理解这个概念。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the Average of n numbers entered by the user ===== \n\n";

    //variable declaration
    int n, i, temp;

    //As we are dealing with the sum, so initializing with 0.
    double sum = 0;

    //As the average of integers can be a fractional value.
    double average = 0;

    //taking input from the command line (user)
    cout << " Enter the number of integers you want to find the average of : ";
    cin >> n;
    cout << "\n\n";

    //taking n numbers as input from the user and adding them to find the final sum
    for (i = 0; i < n; i++)
    {
        cout << "Enter number" << i + 1 << " :  ";
        cin >> temp;

        //add each number to the sum of all the previous numbers to find the final sum
        sum += temp;
    }

    //Finding the average of the entered numbers (atleast one of the varialbe on the RHS has to be double for average to be double)
    average = sum / n;

    cout << "\n\n The Sum of the " << n << " numbers entered by the user is : " << sum << endl;

    cout << "\n\nThe Average of the " << n << " numbers entered by the user is : " << average << endl;

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ adding n numbers entered by the user.

现在让我们看看我们在上面的程序中做了什么。

添加用户在 C++ 中输入的 n 个数字解释如下:

为了更好地理解,让我们分解代码的各个部分。

 //taking n numbers as input from the user and adding them to find the final sum
    for(i=0;i<n;i++)
    {
        cout << "Enter number" << i+1 << " :  ";
        cin >> temp;

        //add each number to the sum of all the previous numbers to find the final sum
        sum += temp;
    }

在上面的代码中,由于我们需要找到所有数字的总和,我们将用户输入的每个数字放入同一个变量中,并将其添加到sum变量中,然后再次对下一个数字使用同一个变量,以此类推。

继续学习:



C++ 程序:无break语句的switch-case

原文:https://www.studytonight.com/cpp-programs/cpp-switch-case-without-break-statement-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示 Switch case 无break语句的概念。

C++ switch-case:

在编程中,开关情况只是多个 if-else 块的一个替代。它仅在满足特定条件时用于执行代码块。break 语句用于阻止代码流进入剩余的块,从而使其在满足单个条件时直接移出开关块。

如果没有break语句,代码将进入匹配案例之后的每个案例。下面代码中讨论的示例将帮助您理解 switch case 中 break 语句提供的功能。

代号:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Switch Case without break statement, in CPP  ===== \n\n";

    //variable to run the Switch case with
    int sw = 1;

    cout << "\n\n***** Entering the Switch case with value 1 ***** \n\n";

    //Logic of Switch case with break statement
    switch (sw)
    {
    case 1:
        cout << "\nInside Case 1\n";
    case 2:
        cout << "\nInside Case 2\n";
    case 3:
        cout << "\nInside Case 3\n";
    case 4:
        cout << "\nInside Case 4\n";
    case 5:
        cout << "\nInside Case 5\n";
    default:
        cout << "\nInside the Default Case\n";
    }

    cout << "\n\n***** Exiting the Switch case ***** \n\n\n";
    return 0;
} 

输出:

C++ switch without break

我们希望这篇文章能帮助你更好地理解 C++ 中不带break语句的 Switch Case 的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:带break语句的switch-case

原文:https://www.studytonight.com/cpp-programs/cpp-switch-case-with-break-statement-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言用 break 语句演示 Switch Case 的概念。

C++ switch-case:

在编程中,switch-case只是多个 if-else 块的一种替代方案。它仅在满足特定条件时用于执行代码块。break 语句用于阻止代码流进入剩余的块,从而使其在满足单个条件时直接移出开关块。

为了更好地理解,我们强烈建议您访问我们在这里的一个帖子:https://www.studytonight.com/c/programs/basic/switch-case,我们在那里详细讨论了这个概念。

代号:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the concept of Switch Case with break statement, in CPP  ===== \n\n";

    //variable to store the operation to be performed
    char operation;

    //variable to store the operands
    int n1, n2, result;

    cout << "\nEnter the operation you want to perform: either + or - or * or / or %: ";
    cin >> operation;

    cout << "\n\n\nEnter the two operands you want to perform the operation on: \n";
    cin >> n1 >> n2;

    //Logic of Switch case with break statement
    switch (operation)
    {
    case '+':
        result = n1 + n2;
        break;
    case '-':
        result = n1 - n2;
        break;
    case '*':
        result = n1 * n2;
        break;
    case '/':
        result = n1 / n2;
        break;
    case '%':
        result = n1 % n2;
        break;

    default:
        cout << "\n\nPlease Enter a Valid Operation from the mentioned list";
        break;
    }

    cout << "\n\nResult obtained from the given data is: " << n1 << operation << n2 << " = " << result << "\n\n\n ";
    return 0;
} 

输出:

C++ switch case with break

我们希望这篇文章能帮助你更好地理解 Switch Case 的概念,包括 break 语句及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:按值传递

原文:https://www.studytonight.com/cpp-programs/cpp-pass-by-value-program

大家好!

在本教程中,我们将学习 C++ 编程语言中的传递值函数调用的工作原理。

传递值函数调用:

在这种类型的函数调用中,仅将变量的实际值传递给已经被调用的函数,而不是存储该值的地址。因此,对该变量所做的任何更改仅对已调用的方法是局部的,除非该变量被声明为全局变量。

要了解这个概念的更多信息,请访问https://www . study south . com/CPP/call-by-value-and-reference . PHP,我们已经解释了按值调用按引用调用函数调用之间的区别。

为了更好地理解,请参考下面给出的注释良好的代码。

代号:

#include <iostream>
#include<vector>
using namespace std;

//Function prototyping as defined after it is being called
int sumOf(int, int);

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the Pass By Value Function Call, in CPP  ===== \n\n";

    //variable declaration
    int num1, num2, addition=0;

    cout << "Enther the two numbers you want to add : \n\n";
    cin >> num1;
    cin >> num2;

    /*
    Demonstrating Multi-line Commenting:
        Passing the values stored in the variables num1 and num2 as parameter to function sumOf().
        The value returned by the function is stored in the variable output
    */

    addition = sumOf(num1, num2);
    cout << "\n\nThe Sum of the two numbers " << num1 << " and " << num2 << ", returned by the function sumOf(), is = " << addition;

    cout << "\n\n\n";

    return 0;
}

// Defining the function sumOf(a,b) which is called by Passing Values and returns the sum of a and b
int sumOf(int n1, int n2)
{
    int sum;
    //Computing the addition of the two values the function is called with
    sum = n1 + n2;

    //Returning the addition to the point where this function is called from
    return sum;
}

输出:

C++ Pass By Value

我们希望这篇文章能帮助您更好地理解 CPP 中的价值召唤概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:按引用调用

原文:https://www.studytonight.com/cpp-programs/cpp-call-by-reference-program

大家好!

在本教程中,我们将以 C++ 编程语言学习通过引用调用函数调用的工作原理。

按引用调用函数调用:

在这种类型的函数调用中,位置或变量的地址被传递给,而不是变量本身的值。

要了解这个概念的更多信息,请访问https://www . study south . com/CPP/call-by-value-and-reference . PHP,我们已经解释了按值调用按引用调用函数调用之间的区别。

为了更好地理解,请参考下面给出的注释良好的代码。

代号:

#include <iostream>
#include<vector>
using namespace std;

//Function prototyping as defined after it is being called.  
// It denotes that the method sumOf() takes two parameters which are pointer to an int and returns int
int sumOf(int *, int *);

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to demonstrate the working of Pass By Reference Function call, in CPP  ===== \n\n";

    //variable declaration
    int num1 = 0, num2 = 0, addition=0;

    cout << "Enther the two numbers you want to add : \n\n";
    cin >> num1;
    cin >> num2;

    /*
    Demonstrating Multi-line Commenting:
        Passing the values stored in the variables num1 and num2 as a parameter to function sumOf().
        The value returned by the function is stored in the variable output
    */

   //It is not always necessary to store the returned value into a variable as it can be directly used as demonstrted below
    cout << "\n\nThe Sum of the two numbers " << num1 << " and " << num2 << ", returned by the function sumOf(), is = " << sumOf(&num1, &num2);

    cout << "\n\n\n";

    return 0;
}

// Defining the function sumOf(a,b) which is called by Passing Values and returns the sum of a and b
int sumOf(int *n1, int *n2)
{
    int sum;
    //Computing the addition of the two values the function is called with
    sum = *n1 + *n2;

    //Returning the addition to the point where this function is called from
    return sum;
}

输出:

C++ Call By Reference

我们希望这篇文章能帮助你更好地理解 C++ 中引用调用的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:在 3 个数字中找出最大和最小

原文:https://www.studytonight.com/cpp-programs/cpp-find-largest-and-smallest-among-3-numbers-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言在用户输入的 3 个数字中找到最大和最小的数字。

这个程序利用这个例子演示了 cpp 编程语言中 if-else 块的流程。

代号:

#include <iostream>
using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to find the Largest and the Smallest number among 3 numbers ===== \n\n";

    //variable declaration
    int n1, n2, n3, smallest, largest;

    //taking input from the command line (user) all at once
    cout << " Enter the three numbers :  \n\n\n";
    cin >> n1 >> n2 >> n3;

    //assign initial value for comparison (as the undefined variables store a random value)
    smallest = n1;
    largest = n2;

    //logic to find the Smallest and the Largest number - Remember, each variable stores only the latest value inserted into it.
    if (n2 < smallest)
    {
        smallest = n2;
    }

    if (n3 < smallest)
    {
        smallest = n3;
    }
    if (n3 > largest)
    {
        largest = n3;
    }

    if (n2 > largest)
    {
        largest = n2;
    }

    cout << "\n\n The Smallest number among ( " << n1 << ", " << n2 << ", " << n3 << " ) is : " << smallest;
    cout << "\n\n The Largest number among ( " << n1 << ", " << n2 << ", " << n3 << " ) is : " << largest;

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ largest and smallest

我们希望这篇文章能帮助你更好地理解如何使用 C++ 中的 if-else 块找到最小和最大的数字。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:循环中的break语句

原文:https://www.studytonight.com/cpp-programs/cpp-break-statement-in-loop-program

大家好!

在本教程中,我们将学习如何用 C++ 编程语言演示循环中 break 语句的概念。

代号:

#include <iostream>

using namespace std;

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " =====  Program to understand the break keyword ===== \n\n";

    // Local variable declaration and initialization:
    int n = 10;

    // do loop execution
    do
    {
        cout << "Value of variable n is : " << n << endl;
        n = n + 1;
        if (n == 15)
        {
            // terminate the loop and execute the next statement following it.

            cout << "\n\nExecuting the break statement and terminating the loop.\n\n";
            break;
        }
    } while (n < 20);

    cout << "The value at which the loop got terminated is : " << n << "\n\n\n";

    return 0;
}

输出:

C++ break in loops

我们希望这篇文章能帮助你更好地理解 C++ 中循环中 break 语句的概念。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:检查数组是否包含重复项

原文:https://www.studytonight.com/cpp-programs/cpp-check-if-the-array-contains-any-duplicates

大家好!

在本教程中,我们将学习如何在 C++ 编程语言中检查给定数组是否包含任何重复的

这是通过首先使用系统定义的sort()方法对数组进行排序来实现的,如下所示。

为了更好地理解,请参考下面给出的注释良好的 C++ 代码。

代号:

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//Program to return true if duplicate is found
bool containsDuplicate(int n[], int m)
{

    //flag to indicate the presence of duplicate
    int f = 0;

    //Sorting the array to check for duplicates
    sort(n, n + m);

    for (int i = 0; i < m - 1; i++)
    {
        if (n[i] == n[i + 1])
        {
            //if duplicate is found then set the flag to 1 and exit the loop
            f = 1;
            break;
        }
    }

    if (f == 1)
        return true;
    else
        return false;
}

int main()
{
    cout << "\n\nWelcome to Studytonight :-)\n\n\n";
    cout << " ===== Program to check if any duplicates are present in the input array  ===== \n\n";

    int i, n1, n2;

    int a1[] = {2, 3, 1, 4, 5, 2, 8, 9};
    int a2[] = {2, 3, 1, 4, 5, 10, 8, 9};

    bool duplicate1 = false;

    bool duplicate2 = false;

    n1 = sizeof(a1) / sizeof(a1[0]);
    n2 = sizeof(a2) / sizeof(a2[0]);

    cout << "\n\nThe elements of the first input array are :\n\n";

    for (i = 0; i < n1; i++)
    {
        cout << a1[i] << "  ";
    }

    duplicate1 = containsDuplicate(a1, n1);

    if (duplicate1)
        cout << "\n\nThe first input array contains duplicate";
    else
        cout << "\n\nThe first input array does not contain any duplicate";

    cout << "\n\n\n\nThe elements of the second input array are :\n\n";

    for (i = 0; i < n2; i++)
    {
        cout << a2[i] << "  ";
    }

    duplicate2 = containsDuplicate(a2, n2);

    if (duplicate2)
        cout << "\n\nThe second input array contains duplicate";
    else
        cout << "\n\nThe second input array does not contain any duplicate";

    cout << "\n\n\n";

    return 0;
} 

输出:

C++ duplicate check

我们希望这篇文章能帮助您更好地理解确定数组是否包含任何副本的概念及其在 C++ 中的实现。如有任何疑问,请随时通过下面的评论区联系我们。

继续学习:



C++ 程序:求一个数的除数

原文:https://www.studytonight.com/cpp-programs/program-to-find-divisor-of-a-number-in-cpp

下面是求给定数除数的程序。

#include<iostream.h>
#include<conio.h>

int main()
{
    int i, n1;
    clrscr() ;
    cout<<"Enter the number to find it's divisors : " ;
    cin>>n1 ;
    cout<<"\nThe divisors are :\n") ;
    for(i = 1 ; i <= n1 ; i++)
        if(n1 % i == 0)
            cout<<"\t"<<i ;
    getch() ;
    return 0;
}

输入数字找到它的除数:21
除数是:
1 3 7 21



C++ 程序:执行继承

原文:https://www.studytonight.com/cpp-programs/program-to-perform-inheritance-in-cpp

下面是用 C++ 执行继承的程序。

#include <iostream.h>
#include<stdio.h>
#include<conio.h>

class Shape 
{
    public:
    void setWidth(int w) 
    {
	    width = w;
    }

    void setHeight(int h) 
    {
	    height = h;
    }

    protected:
    int width;
    int height;
};

class PaintCost  
{
    public:
    int getCost(int area) 
    {
	    return area * 70;
    }
};

class Rectangle: public Shape, public PaintCost 
{
    public:
    int getArea() 
    {
	    return (width * height);
    }
};

int main(void) 
{
    Rectangle Rect;
    int area;
    Rect.setWidth(5);
    Rect.setHeight(7);

    area = Rect.getArea();
    cout << "Total area: " << Rect.getArea() << endl;

    cout << "Total paint cost: $" << Rect.getCost(area) << endl;
    getch();
    return 0;
}

总面积:35
油漆总成本:2450 美元



C++ 程序:执行矩阵转置

原文:https://www.studytonight.com/cpp-programs/program-to-perform-transpose-of-a-matrix-in-cpp

下面是执行矩阵转置的程序。

#include<iostream.h>

void main()
{
    int mat1[3][3], mat2[3][3];
    int i, j, k;
    cout<<"Enter the elements of Matrix(3X3) : ";
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            cin>>mat1[i][j];
        }
    }
    cout<<"\nMatrix is : "<<endl;
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            cout<<mat1[i][j]<<" ";
        }
        cout<<endl;
    }
    //Transposing Matrices
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            mat2[i][j]=mat1[j][i];
        }
    }
    cout<<"\nTransposed matrix is : "<<endl;
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            cout<<mat2[i][j]<<" ";
        }
        cout<<endl;
    }
}

输入矩阵的元素(3x 3):1
2
3
4
5
6
7
8
9
矩阵为:
1 2 3
4 5 6
7 8 9
转置矩阵为:
1 4 7
2 5 8
3 6 9



C++ 程序:对给定二维数组执行各种矩阵运算

原文:https://www.studytonight.com/cpp-programs/program-to-perform-various-matrix-operation-on-a-given-2d-array

下面是对给定的二维数组执行各种矩阵运算的程序。

#include<iostream.h>
#include<conio.h>

int main()
{
    clrscr();
    int a[50][50],b[50][50],c[50][50],i,j,m,n,o,p,l=1,r;
    cout<<"Enter case:\n";
    cin>>r;
    switch(r)
    {
        //ADDITION
        case 1:
            cout<<"\nEnter the order of matrix a (must be m*n): "<<endl;
            cin>>m;
            cout<<"* \n";
            cin>>n;
            cout<<"Enter the order of matrix b (must be o*p): "<<endl;
            cin>>o;
            cout<<"* \n";
            cin>>p;
            if (m==o&&n==p)
            {
                cout<<"Addition possible "<<endl;
            }
            else
            {
                cout<<"Addition not possible ";
                l=0;
            }

            if(l)
            {
                cout<<"\n\nEnter the elements of matrix 1: "<<endl;
                for (i=1;i<=m;i++)
                {
                    for (j=1;j<=n;j++)
                        cin>>a[i][j];
                }
                cout<<"Elements of matrix 1 are: ";
                for (i=1;i<=m;i++)
                {
                    cout<<endl;
                    for (j=1;j<=n;j++)
                        cout<<a[i][j]<<" ";
                }
                cout<<"\nEnter the elements of matrix 2: "<<endl;
                for (i=1;i<=o;i++)
                {
                    for (j=1;j<=p;j++)
                        cin>>b[i][j];
                }
                cout<<"Elements of matrix 2 are: ";
                for (i=1;i<=o;i++)
                {
                    cout<<endl;
                    for (j=1;j<=p;j++)
                        cout<<b[i][j]<<" ";
                }
                cout<<"\n\n\nAddition:\nc=a+b=";
                for (i=1;i<=m;i++)
                {
                    for (j=1;j<=n;j++)
                    {
                        c[i][j]=a[i][j]+b[i][j];
                    }
                }
                for (i=1;i<=m;i++)
                {
                    cout<<endl;
                    for (j=1;j<=n;j++)
                        cout<<c[i][j]<<" ";
                }
            }
            break;

        //SUBTRACTION
        case 2:
            cout<<"\nEnter the order of matrix a (must be m*n): "<<endl;
            cin>>m;
            cout<<"* \n";
            cin>>n;
            cout<<"Enter the order of matrix b (must be o*p): "<<endl;
            cin>>o;
            cout<<"* \n";
            cin>>p;
            if (m==o&&n==p)
            {
                cout<<"Subtracion possible "<<endl;
            }
            else
            {
                cout<<"Subtraction not possible ";
                l=0;
            }

            if(l)
            {
                cout<<"\n\nEnter the elements of matrix 1: "<<endl;
                for (i=1;i<=m;i++)
                {
                    for (j=1;j<=n;j++)
                        cin>>a[i][j];
                }
                cout<<"Elements of matrix 1 are: ";
                for (i=1;i<=m;i++)
                {
                    cout<<endl;
                    for (j=1;j<=n;j++)
                        cout<<a[i][j]<<" ";
                }
                cout<<"\nEnter the elements of matrix 2: "<<endl;
                for (i=1;i<=o;i++)
                {
                    for (j=1;j<=p;j++)
                        cin>>b[i][j];
                }
                cout<<"Elements of matrix 2 are: ";
                for (i=1;i<=o;i++)
                {
                    cout<<endl;
                    for (j=1;j<=p;j++)
                        cout<<b[i][j]<<" ";
                }
                cout<<"\n\n\nSubtraction:\nc=a-b=";
                for (i=1;i<=m;i++)
                {
                    for (j=1;j<=n;j++)
                    {
                        c[i][j]=a[i][j]-b[i][j];
                    }
                }
                for (i=1;i<=m;i++)
                {
                    cout<<endl;
                    for (j=1;j<=n;j++)
                        cout<<c[i][j]<<" ";
                }
            }
            break;

        //MULTIPLICATION
        case 3:
            cout<<"\nEnter the order of matrix a (must be m*n): "<<endl;
            cin>>m;
            cout<<"* \n";
            cin>>n;
            cout<<"Enter the order of matrix b (must be o*p): "<<endl;
            cin>>o;
            cout<<"* \n";
            cin>>p;
            if (n==o)
            {
                cout<<"Multiplication possible "<<endl;
            }
            else
            {
                cout<<"Multiplication not possible ";
                l=0;
            }

            if(l)
            {
                cout<<"\n\nEnter the elements of matrix 1: "<<endl;
                for (i=1;i<=m;i++)
                {
                    for (j=1;j<=n;j++)
                        cin>>a[i][j];
                }
                cout<<"Elements of matrix 1 are: ";
                for (i=1;i<=m;i++)
                {
                    cout<<endl;
                    for (j=1;j<=n;j++)
                        cout<<a[i][j]<<" ";
                }
                cout<<"\nEnter the elements of matrix 2: "<<endl;
                for (i=1;i<=o;i++)
                {
                    for (j=1;j<=p;j++)
                        cin>>b[i][j];
                }
                cout<<"Elements of matrix 2 are: ";
                for (i=1;i<=o;i++)
                {
                    cout<<endl;
                    for (j=1;j<=p;j++)
                        cout<<b[i][j]<<" ";
                }
                cout<<"\n\n\nMultiplication:\nc=aXb=";
                for (i=1;i<=m;i++)
                {
                    for (j=1;j<=p;j++)
                    {
                        c[i][j]=0;
                        for (int k=1;k<=n;k++)
                        {
                            c[i][j]=c[i][j]+(a[i][k]*b[k][j]);
                        }
                    }
                }
                for (i=1;i<=m;i++)
                {
                    cout<<endl;
                    for (j=1;j<=p;j++)
                        cout<<c[i][j]<<" ";
                }
            }
            break;
        // default case
        default:
            cout<<"Wrong choice";
    }
    getch();
    return 0;
}

输入大小写:
3
输入矩阵 a 的顺序(必须是 mn):
2
*
3
输入矩阵 b 的顺序(必须是 o
p):
3
*
4
乘法可能
输入矩阵 1 的元素:
1 2 3 4 5 6
矩阵 1 的元素为:
1 2 3
4 5 6
输入矩阵 2 的元素:
1 2 3 4 5 6 7 8 9 10 11 12
矩阵 2 的元素为:
1 2 3 4
5 6 7 8
9 10 11 12



C++ 程序:打印帕斯卡三角形

原文:https://www.studytonight.com/cpp-programs/program-to-print-pascal-triangle-in-cpp

下面是打印帕斯卡三角形的程序。

#include<conio.h>
#include<iostream.h>

int main()
{
	int n,i,j,c,k,place;

	cout<<"Enter the no of rows: "<<endl;
	cin>>n;
	cout<<" \n\nPASCAL TRIANGLE"<<endl;
	cout<<"\n\n";
	place=n;
		for(i=0;i<n;i++){
			c=1;
			for(k=place;k>=0;k--)
				cout<<" ";

				place--;
			for(j=0;j<=i;j++){
					cout<<c<<" ";
					c=(c*(i-j)/(j+1));
				}
			cout<<"\n";

	    }
getch();
return 0;
}

输出



C++ 程序:使用*打印全金字塔

原文:https://www.studytonight.com/cpp-programs/program-to-print-full-pyramid-using-in-cpp

以下是使用*打印全金字塔的程序。

#include<iostream.h>

int main()
{
    int space, rows;

    cout <<"Enter number of rows: ";
    cin >> rows;

    for(int i = 1, k = 0; i <= rows; ++i, k = 0)
    {
        for(space = 1; space <= rows-i; ++space)
        {
            cout <<"  ";
        }

        while(k != 2*i-1)
        {
            cout << "* ";
            ++k;
        }
        cout << endl;
    }    
getch();
return 0 ;
}

输出



C++ 程序:简单计算器

原文:https://www.studytonight.com/cpp-programs/program-for-simple-calculator-in-cpp

下面是使用switch语句的简单计算器程序。

#include<iostream.h>

int main()
{
    char op;
    float num1, num2;
    cout << "Enter operator either + or - or * or /: ";
    cin >> op;
    cout << "\nEnter two operands: ";
    cin >> num1 >> num2;
    switch(op)
    {
        case '+':
            cout <<”\nResult is: ”<< num1+num2;
            break;

        case '-':
            cout <<”\nResult is: ”<< num1-num2;
            break;

        case '*':
            cout <<”\nResult is: ”<<num1*num2;
            break;

        case '/':
            cout <<”\nResult is: ”<<num1/num2;
            break;

        default:
            // If the operator is other than +, -, * or /, error message is shown
            cout<<"Error! operator is not correct";
            break;
    }
getch();
return 0 ;
}

输入运算符+或-或*或/ : -
输入两个操作数:3.4
8.4
结果为:-5.0



C++ 程序:打印斐波那契数列

原文:https://www.studytonight.com/cpp-programs/program-to-print-fibonacci-series-in-cpp

以下是查找斐波那契数列的程序。

#include<iostream.h>

int main()
{
    int n, t1=0, t2=1, nextTerm=0;

    cout << "Enter the number of terms: ";
    cin >> n;
    cout << "Fibonacci Series: ";

    for (int i=1; i <= n; ++i)
    {
        if(i == 1)
        {
            cout << " " << t1;
            continue;
        }
        if(i == 2)
        {
            cout << t2 << " ";
            continue;
        }
        nextTerm = t1 + t2;
        t1 = t2;
        t2 = nextTerm;

        cout << nextTerm << " ";
    }
    getch();
    return 0 ;
}

输入项数:10
斐波那契数列:0 1 2 3 5 8 13 21 34



C++ 程序:求三个数中最大值

原文:https://www.studytonight.com/cpp-programs/program-to-find-greatest-of-three-numbers-in-cpp

下面是找出三个数字中最大值的程序。

#include<iostream.h>
#include<conio.h>

int main()
{
    float n1, n2, n3;
    cout << "Enter three numbers: ";
    cin >> n1 >> n2 >> n3;
    if (n1 >= n2 && n1 >= n3)
    {
        cout << "Largest number: " << n1;
    }
    if(n2 >= n1 && n2 >= n3)
    {
        cout << "Largest number: " << n2;
    }
    if(n3 >= n1 && n3 >= n2)
    {
        cout << "Largest number: " << n3;
    }
    getch();
    return 0;
} 

输入三个数字:34 45 56
最大数字:56



数据结构

数据结构和算法基础知识

数据结构和算法导论

原文:https://www.studytonight.com/data-structures/introduction-to-data-structures

数据结构是一种收集和组织数据的方式,我们可以有效地对这些数据执行操作。数据结构是根据某种关系呈现数据元素,以便更好地组织和存储。例如,我们有一些数据,玩家的名字“Virat”和年龄 26。这里的“Virat”是字符串数据类型,26 是整数数据类型。

我们可以将这些数据组织成类似玩家记录的记录,其中会同时包含玩家的姓名和年龄。现在我们可以将玩家的记录收集并存储在一个文件或数据库中作为数据结构。例如:“多尼”30,“甘比尔”31,“塞瓦格”33

如果你知道面向对象编程的概念,那么class也做同样的事情,它在一个单独的实体下收集不同类型的数据。唯一不同的是,数据结构提供了有效访问和操作数据的技术。

在简单的语言中,数据结构是被编程来存储有序数据的结构,因此可以很容易地对其执行各种操作。它表示要在内存中组织的数据知识。它的设计和实现应该降低复杂度,提高效率。


数据结构的基本类型

如上所述,任何可以存储数据的东西都可以被称为数据结构,因此整型、浮点型、布尔型、字符型等都是数据结构。它们被称为原始数据结构

然后,我们还有一些复杂的数据结构,用于存储大型和连接的数据。抽象数据结构的一些例子有:

  • 链表
  • 图表
  • 栈、队列等。

所有这些数据结构都允许我们对数据执行不同的操作。我们根据需要的操作类型来选择这些数据结构。我们将在后面的课程中更详细地研究这些数据结构。

Introduction to Data Structures

数据结构也可以根据以下特征进行分类:

| 特性 | 描述 |
| 线性的 | 在线性数据结构中,数据项以线性顺序排列。示例:数组 |
| 非线性的 | 在非线性数据结构中,数据项不是按顺序排列的。示例: |
| 同质的 | 在同构数据结构中,所有的元素都是相同的类型。示例:数组 |
| 非均匀的 | 在非同构数据结构中,元素可以是同一类型的,也可以不是同一类型的。示例:结构 |
| 静态 | 静态数据结构是那些在编译时其大小和结构相关的内存位置是固定的。示例:数组 |
| 动态的 | 动态结构是那些根据程序需求及其执行而扩展或收缩的结构。此外,它们相关联的存储位置也会改变。示例:使用指针创建的链表 |


什么是算法?

算法是一组有限的指令或逻辑,按顺序编写,以完成特定的预定义任务。算法不是完整的代码或程序,它只是一个问题的核心逻辑(解决方案),可以用伪代码这样的非正式高层描述来表达,也可以用流程图来表达。

每个算法必须满足以下属性:

  1. 输入 -算法应该有 0 个或更多的外部输入。
  2. 输出 -至少应获得 1 个输出。
  3. 明确性 -算法的每一步都要清晰明确。
  4. 有限性 -算法应该有有限步数。
  5. 正确性 -算法的每一步都必须产生正确的输出。

如果一个算法执行起来花费的时间更少,消耗的内存空间更少,那么它就被认为是高效和快速的。算法的性能是根据以下属性来衡量的:

  1. 时间复杂度
  2. 空间复杂度

空间复杂度

它是算法在执行过程中所需的内存空间量。对于多用户系统和内存有限的情况,必须认真考虑空间复杂度。

算法通常需要空间用于以下组件:

  • 指令空间:存储程序可执行版本所需的空间。这个空间是固定的,但是根据程序中的代码行数而变化。
  • 数据空间:存储所有常量和变量(包括临时变量)值所需的空间。
  • 环境空间:存储恢复暂停功能所需的环境信息所需的空间。

要详细了解空间复杂度,请跳到空间复杂度教程。


时间复杂度

时间复杂度是一种表示程序运行到完成所需时间的方法。一般来说,将所需的时间保持在最短是一个很好的做法,这样我们的算法就可以在尽可能短的时间内完成它的执行。我们将在后面的章节中详细研究时间复杂度。


注意:在深入数据结构之前,你应该对编程有很好的了解,无论是在 C 还是在 C++ 或者 Java 或者 Python 等等。



渐近符号

原文:https://www.studytonight.com/data-structures/aysmptotic-notations

当从时间和空间的角度分析任何算法的复杂度时,我们永远无法提供一个精确的数字来定义算法所需的时间和空间,而是使用一些标准符号来表示,也称为渐近符号

当我们分析任何算法时,我们通常会得到一个公式来表示执行所需的时间量或计算机运行算法代码行所需的时间、内存访问次数、比较次数、占用内存空间的临时变量等。这个公式经常包含不重要的细节,这些细节并不能真正告诉我们任何关于运行时间的信息。

举个例子,如果某算法的时间复杂度为 T(n) = (n 2 + 3n + 4),这是一个二次方程。对于较大的n值,3n + 4部分与n<sup>2</sup>部分相比将变得无关紧要。

Asymptotic Notations example

n = 1000 时,n<sup>2</sup>10000003n + 43004

此外,当我们比较两种算法的执行时间时,高阶项的常量系数也被忽略。

对于任何大于200n值,需要200n<sup>2</sup>时间的算法将比需要n<sup>3</sup>时间的其他算法更快。因为我们只对函数增长的渐近行为感兴趣,所以常量因子也可以忽略。


什么是渐近行为

单词渐近意味着任意接近一个值或曲线(即,当采取某种限制时)。

记得高中学习关于极限的内容,这个是一样的。

唯一的区别是,这里我们不需要找到任何表达式的值,其中n接近任何有限的数字或无穷大,但是在渐近符号的情况下,我们使用相同的模型来忽略常量因子和表达式的不重要部分,以在单个系数中设计更好的方法来表示算法的复杂度,从而可以容易地进行算法之间的比较。

让我们举个例子来理解这一点:

如果我们有两个算法,用下面的表达式表示它们执行所需的时间,那么:

表达式 1 : (20n 2 + 3n - 4)

表达式 2 : (n 3 + 100n - 2)

现在,根据渐近表示法,我们应该只关心函数将如何随着n(输入)值的增长而增长,这将完全取决于表达式 1 的n<sup>2</sup>和表达式 2 的n<sup>3</sup>。因此,我们可以清楚地说,运行时间由表达式 2 表示的算法将比另一个算法增长得更快,简单地通过分析最高功率系数并忽略其他常量(20n 中的 20 个 2 )和表达式的不重要部分(3n - 4100n - 2)。

抛开不太重要的部分背后的主要思想是让事情变得可管理

我们需要做的是,首先分析算法,找出一个表达式来定义它的时间要求,然后分析该表达式将如何随着输入(n)的增长而增长。


渐近符号的类型

随着输入的增加,我们使用三种渐近符号来表示任何算法的增长:

  1. 大θ(θ)
  2. 大哦(O)
  3. 大ω(ω)

严格界限:θ

当我们说严格界限时,我们的意思是由大θ符号表示的时间复杂度就像算法的实际执行时间的平均值或范围。

例如,如果对于某些算法,时间复杂度由表达式 3n 2 + 5n 来表示,并且我们使用 Big-θ符号来表示,那么时间复杂度将是θ(n2,忽略常量系数并去除不重要的部分,即 5n。

这里,在上面的例子中,θ(n2)的复杂度意味着,任何输入n的平均时间将保持在,k1 * n<sup>2</sup>k2 * n<sup>2</sup>之间,其中 k1、k2 是两个常量,因此紧密地绑定了表示算法增长的表达式。

Big thets representation


上限:大 0

这种符号被称为算法的上限,或算法的最坏情况。

它告诉我们,对于任何输入值n,某个函数都不会超过指定的时间。

问题是,当我们已经有了大θ表示法时,为什么还需要这种表示法,大θ表示法表示任何算法的紧束缚运行时间。让我们举一个小例子来理解这一点。

考虑线性搜索算法,其中我们遍历一个数组元素,一个接一个地搜索给定的数字。

最差情况中,从数组的前面开始,我们在末尾找到要搜索的元素或个数,这将导致n的时间复杂度,其中n表示元素总数。

但有可能发生的是,我们搜索的元素是数组的第一个元素,这种情况下时间复杂度为1

现在在这种情况下,说线性搜索的大θ或紧界时间复杂度是θ(n),将意味着所需时间将总是与n相关,因为这是表示平均时间复杂度的正确方式,但是当我们使用大 O 符号时,我们的意思是说时间复杂度是 O(n),这意味着时间复杂度永远不会超过n,定义了上限,因此说它可以小于或等于n,这是正确的表示。

这就是原因,大多数时候你会看到 Big-O 符号被用来表示任何算法的时间复杂度,因为它更有意义。


下限:欧米茄

大ω符号用于定义任何算法的下界或者我们可以说是任何算法的最佳情况

这总是指示任何算法对于所有输入值所需的最短时间,因此是任何算法的最佳情况。

简而言之,当我们以大ω的形式表示任何算法的时间复杂度时,我们意味着该算法至少需要这么多时间来完成它的执行。肯定会比这花费更多的时间。



算法的空间复杂度

原文:https://www.studytonight.com/data-structures/space-complexity-of-algorithms

每当一个问题的解决方案被写入时,需要一些内存来完成。对于任何算法,存储器可用于以下目的:

  1. 变量(包括常量值、临时值)
  2. 程序指令
  3. 执行

空间复杂度是算法执行和产生结果所使用的内存量(包括算法的输入值)。

有时候辅助空间会和空间复杂度混淆。但是辅助空间是算法在执行过程中使用的额外空间或临时空间。

空间复杂度 = 辅助空间+输入空间


执行时的内存使用

执行时,算法使用内存空间有三个原因:

  1. Instruction Space

    这是用于保存指令编译版本的内存量。

  2. Environmental Stack

    有时一个算法(函数)可能在另一个算法(函数)内部被调用。在这种情况下,当前变量被推到系统栈上,等待进一步执行,然后调用内部算法(函数)。

    例如,如果一个函数A()在其内部调用函数B(),那么函数A()的所有变量将被暂时存储在系统栈上,而函数B()在函数A()内部被调用和执行。

  3. Data Space

    变量和常量使用的空间量。

但是在计算任何算法的空间复杂度时,我们通常只考虑数据空间,而忽略了指令空间环境栈


计算空间复杂度

为了计算空间复杂度,我们需要知道不同类型的数据类型变量所使用的内存值,这通常因不同的操作系统而异,但是计算空间复杂度的方法保持不变。

| 类型 | 大小 |
| bool,char,无符号字符,有符号字符,__int8 | 1 字节 |
| __int16,短,无符号短,wchar_t,__wchar_t | 2 字节 |
| float,__int32,int,无符号 int,long,无符号 long | 4 字节 |
| double,__int64,long double,long long | 8 字节 |

现在让我们通过几个例子来学习如何计算空间复杂度:

{
    int z = a + b + c;
    return(z);
}

在上面的表达式中,变量abcz都是整数类型,因此它们将各占用 4 个字节,因此总内存需求为(4(4) + 4) = 20 bytes,这额外的 4 个字节用于返回值。并且因为这个空间需求对于上面的例子是固定的,因此它被称为恒定空间复杂度

我们再举一个例子,这次有点复杂,

// n is the length of array a[]
int sum(int a[], int n)
{
	int x = 0;		// 4 bytes for x
	for(int i = 0; i < n; i++)	// 4 bytes for i
	{	
	    x  = x + a[i];		
	}
	return(x);
}
  • 在上面的代码中,数组a[]元素需要4*n字节的空间。
  • xni和返回值各 4 个字节。

因此,总内存需求为(4n + 12),随着输入值n的增加而线性增加,因此称为线性空间复杂度。

类似地,随着算法复杂度的增加,我们也可以有二次和其他复杂的空间复杂度。

但是我们应该始终专注于以保持空间复杂度最小的方式编写算法代码。



算法的时间复杂度

原文:https://www.studytonight.com/data-structures/time-complexity-of-algorithms

对于任何已定义的问题,可以有 N 个解。总的来说是这样的。如果我有问题,我和我所有的朋友讨论这个问题,他们都会给我建议不同的解决方案。我必须根据情况决定哪种解决方案是最好的。

同样,对于任何必须用程序来解决的问题,可以有无限多种解决方案。让我们举一个简单的例子来理解这一点。下面我们有两种不同的算法来求一个数的平方(有一段时间,忘记任何数的平方n都是n*n):

这个问题的一个解决方案可以是,运行一个循环n次,从数字n开始,每次加上n

/* 
    we have to calculate the square of n
*/
for i=1 to n
    do n = n + n
// when the loop ends n will hold its square
return n

或者,我们可以简单地用一个数学运算符*来求平方。

/* 
    we have to calculate the square of n
*/
return n*n

在上面两个简单的算法中,您看到了一个问题如何可以有多个解决方案。第一个解决方案需要一个循环来执行n次,而第二个解决方案使用一个数学运算符*来返回一行中的结果。那么哪一个是更好的方法,当然是第二个。


什么是时间复杂度?

算法的时间复杂度表示程序运行到完成所需的总时间。

算法的时间复杂度最常用大 O 符号来表示。这是表示时间复杂度的渐近符号。我们将在下一个教程中详细研究它。

时间复杂度通常通过计算任何算法完成执行的基本步骤数来估计。就像上面的例子一样,对于第一个代码,循环将运行n次,因此时间复杂度至少为n,并且随着n值的增加,所花费的时间也将增加。而对于第二个代码,时间复杂度是不变的,因为它永远不会依赖于n的值,它总是以 1 步给出结果。

由于算法的性能可能随着不同类型的输入数据而变化,因此对于算法,我们通常使用算法的最坏情况时间复杂度,因为这是任何输入大小所花费的最大时间。


计算时间复杂度

现在让我们进入下一个与时间复杂度相关的大主题,即如何计算时间复杂度。有时候会变得很混乱,但我们会试着用最简单的方式来解释。

现在计算时间复杂度最常用的度量是大 O 表示法。这去除了所有的恒定因素,以便当 N 接近无穷大时,可以相对于 N 估计运行时间。一般来说,你可以这样想:

statement;

以上我们有一个单一的声明。它的时间复杂度将是常量。语句的运行时间不会因 n 而改变

for(i=0; i < N; i++)
{
    statement;
}

上述算法的时间复杂度将为线性。循环的运行时间与 N 成正比,当 N 翻倍时,运行时间也翻倍。

for(i=0; i < N; i++) 
{
    for(j=0; j < N;j++)
    { 
    statement;
    }
}

这一次,上述代码的时间复杂度将是二次。两个循环的运行时间与 N 的平方成正比,当 N 翻倍时,运行时间增加 N * N。

while(low <= high) 
{
    mid = (low + high) / 2;
    if (target < list[mid])
        high = mid - 1;
    else if (target > list[mid])
        low = mid + 1;
    else break;
}

这是一种将一组数字分成两半的算法,用于搜索特定的字段(我们将在后面详细研究)。现在,这个算法将有一个对数时间复杂度。算法的运行时间与 N 可以除以 2 的次数成正比(这里 N 为高低)。这是因为算法每次迭代都会将工作区域分成两半。

void quicksort(int list[], int left, int right)
{
    int pivot = partition(list, left, right);
    quicksort(list, left, pivot - 1);
    quicksort(list, pivot + 1, right);
}

把前面的算法往前推,上面我们有一个快速排序的小逻辑(这个我们后面会详细研究)。现在在快速排序中,我们每次都将列表分成两半,但是我们重复迭代 N 次(其中 N 是列表的大小)。因此时间复杂度将是 N*log( N ) 。运行时间由 N 个对数循环(迭代或递归)组成,因此该算法是线性和对数的组合。

注:一般情况下,一维每一项做一件事是线性的,二维每一项做一件事是二次的,把工作区域对半划分是对数的。


时间复杂度的符号类型

Now we will discuss and understand the various notations used for Time Complexity.

  1. 大哦表示“少于或等于”<表达>迭代。
  2. 大ω表示“大于或等于”<表达式>迭代。
  3. 大θ表示“”<表达>迭代。
  4. 小 Oh 表示“”<表达式>迭代次数少。
  5. 小欧米茄表示多于<表示>迭代。

用例子理解时间复杂度的符号

O(表达式)是比表达式增长更慢或以相同速度增长的一组函数。它表示算法对所有输入值要求的最大值。它代表了算法时间复杂度的最坏情况。

Omega(表达式)是比表达式增长更快或以相同速度增长的一组函数。它表示算法对所有输入值所需的最短时间。它代表了算法时间复杂度的最佳情况。

θ(表达式)由位于 0(表达式)和ω(表达式)中的所有函数组成。它表示算法的平均界限。它代表算法时间复杂度的平均情况。

假设你已经计算出一个算法需要 f(n)次运算,其中,

f(n) = 3*n^2 + 2*n + 4\.   // n^2 means square of n

由于该多项式的增长速度与n2T3 相同,因此可以说函数 f 位于集合θ(n2)中。(同样的道理也存在于 O(n 2 )欧米茄(n 2 )** 这两套里面。)**

最简单的解释就是,因为θ表示这个表达是一样的。因此,当 f(n)n 2 的因子增长时,时间复杂度可以最好地表示为θ(n2)

既然我们已经学习了算法的时间复杂度,那么你也应该学习一下算法的空间复杂度及其重要性。



基本算法

搜索算法简介

原文:https://www.studytonight.com/data-structures/search-algorithms

甚至没有一天的通行证,当我们不必在我们的日常生活中寻找一些东西,车钥匙,书,笔,手机充电器和什么没有。计算机的生命也是如此,其中存储着如此多的数据,以至于每当用户要求一些数据时,计算机都必须搜索它的内存来寻找数据,并使其对用户可用。而且电脑有它自己的快速搜索内存的技术,你可以在我们的操作系统教程系列中了解更多。

如果你必须写一个程序来搜索一个数组中的一个给定的数字呢?你会怎么做?

要搜索给定数组中的元素,有两种流行的算法:

  1. 线性搜索
  2. 二进位检索

线性搜索

线性搜索是一种非常基本和简单的搜索算法。在线性搜索中,我们通过从头开始遍历数组来搜索给定数组中的元素或值,直到找到所需的元素或值。

它将待搜索的元素与数组中存在的所有元素进行比较,当元素匹配成功时,它返回数组中元素的索引,否则返回-1

当列表中的元素较少时,线性搜索适用于未排序或无序的列表。


线性搜索算法的特点

  1. 它用于未排序和无序的元素小列表。
  2. 它的时间复杂度为 O(n) ,也就是说时间线性依赖于元素的数量,这不算差,但也没那么好。
  3. 它有一个非常简单的实现。

我们将在下一个教程中实现线性搜索算法。


二进位检索

二分搜索用于排序数组或列表。在二分搜索,我们遵循以下步骤:

  1. 我们从比较要搜索的元素和列表/数组中间的元素开始。
  2. 如果我们得到匹配,我们返回中间元素的索引。
  3. 如果我们没有得到匹配,我们检查要搜索的元素在值上是小于还是大于中间元素。
  4. 如果要搜索的元素/数字的值大于中间数字,那么我们选择中间元素右侧的元素(当列表/数组被排序时,因此在右侧,我们将拥有大于中间数字的所有数字),并从步骤 1 重新开始。
  5. 如果要搜索的元素/数字的值小于中间的数字,那么我们选择中间元素左侧的元素,并从步骤 1 重新开始。

当一个数组中有大量元素并且它们被排序时,二分搜索是有用的。

所以二分搜索工作的一个必要条件是列表/数组应该被排序。


二分搜索的特色

  1. 在大的排序数组中搜索是很棒的。
  2. 它的时间复杂度为 O(log n) ,这是一个非常好的时间复杂度。我们将在二分搜索教程中详细讨论这一点。
  3. 它的实现很简单。


线性搜索算法

原文:https://www.studytonight.com/data-structures/linear-search-algorithm

线性搜索是一种非常基本和简单的搜索算法。在线性搜索中,我们通过从头开始遍历数组来搜索给定数组中的元素或值,直到找到所需的元素或值。

正如我们在之前的教程中了解到的,线性搜索算法的时间复杂度是 O(n) ,我们将对其进行分析,看看实现后为什么是 O(n)


实现线性搜索

以下是我们将遵循的实施步骤:

  1. 使用for循环遍历数组。
  2. 在每次迭代中,将target值与数组的当前值进行比较。
    • 如果值匹配,则返回数组的当前索引。
    • 如果值不匹配,请继续下一个数组元素。
  3. 如果没有找到匹配,返回-1

要在下面给出的数组中搜索数字 5 ,线性搜索将从给定数组中的第一个元素开始按顺序一步步进行。

Linear search implementation array example

/* 
    below we have implemented a simple function 
    for linear search in C

    - values[] => array with all the values
    - target => value to be found
    - n => total number of elements in the array
*/
int linearSearch(int values[], int target, int n)
{
    for(int i = 0; i < n; i++)
    {
        if (values[i] == target) 
        {       
            return i; 
        }
    }
    return -1;
}

有输入的一些例子

输入:值[] = {5,34,65,12,77,35}目标= 77 输出:4 输入:值[] = {101,392,1,54,32,22,90,93}目标= 200 输出:-1(未找到)


最后的想法

我们知道你喜欢线性搜索,因为它实现起来非常简单,但是它实际上并没有被使用,因为二分搜索比线性搜索快得多。所以让我们进入下一个教程,在那里我们将了解更多关于二分搜索的知识。



二分搜索算法

原文:https://www.studytonight.com/data-structures/binary-search-algorithm

二分搜索应用于大尺寸的排序数组或列表。与其他排序算法相比, O(log n) 的时间复杂度使其非常快。唯一的限制是必须对元素的数组或列表进行排序,二分搜索算法才能对其进行处理。


实现二分搜索算法

以下是我们将遵循的实施步骤:

  1. 从中间元素开始:
    • 如果目标值等于数组的中间元素,则返回中间元素的索引。
    • 如果不是,则将中间元素与目标值进行比较,
      • 如果目标值大于中间索引中的数字,则选择中间索引右侧的元素,并从步骤 1 开始。
      • 如果目标值小于中间索引中的数字,则选择中间索引左侧的元素,并从步骤 1 开始。
  2. 找到匹配项时,返回匹配元素的索引。
  3. 如果没有找到匹配,则返回-1
/*
    function for carrying out binary search on given array
    - values[] => given sorted array
    - len => length of the array
    - target => value to be searched
*/
int binarySearch(int values[], int len, int target)
{
    int max = (len - 1);
    int min = 0;

    int guess;  // this will hold the index of middle elements
    int step = 0;  // to find out in how many steps we completed the search

    while(max >= min)
    {
        guess = (max + min) / 2;
        // we made the first guess, incrementing step by 1
        step++;

        if(values[guess] ==  target)
        {
            printf("Number of steps required for search: %d \n", step);
            return guess;
        }
        else if(values[guess] >  target) 
        {
            // target would be in the left half
            max = (guess - 1);
        }
        else
        {
            // target would be in the right half
            min = (guess + 1);
        }
    }

    // We reach here when element is not 
    // present in array
    return -1;
}

int main(void)
{
    int values[] = {13, 21, 54, 81, 90};
    int n = sizeof(values) / sizeof(values[0]);
    int target = 81;
    int result = binarySearch(values, n, target);
    if(result == -1)
    {  
        printf("Element is not present in the given array.");
    }
    else
    {
        printf("Element is present at index: %d", result);
    }
    return 0;
}

希望以上代码清晰,如有疑惑,请在我们 Q & A 论坛发帖提问。

现在让我们试着理解,为什么二分搜索的时间复杂度是 O(log n) 以及我们如何在不做任何计算的情况下,使用二分搜索计算从给定数组中搜索一个元素所需的步骤数。超级简单!你准备好了吗?


二分搜索的时间复杂度O(log n)

当我们说时间复杂度是log n时,我们实际上是指log<sub>2</sub> n,虽然对数的基数在渐近符号中并不重要,但是为了更好地理解这一点,我们通常考虑基数为 2。

我们先来了解一下log<sub>2</sub>(n)是什么意思。

表达式:log 2 (n) - - - - - - - - - - - -对于 n = 2:log2(21)= 1 Output = 1------------对于 n = 4 log 2 (2 2 ) = 2 Output = 2 - - - - - - - - - - - - - - -对于 n = 8 log2(23)= 3 Output = 3------------对于 n = 256 log2(28) = 8 输出= 8 - - - - - -对于 n = 2048 log2(211)= 11 输出= 11

既然我们知道了log<sub>2</sub>(n)如何与n的不同值一起工作,那么我们就更容易将其与二分搜索算法的时间复杂度联系起来,也更容易理解我们如何能够找出使用二分搜索搜索任意数量的n的任意值所需的步骤数。


计算步数

正如我们已经看到的,每出现一个不正确的guess,二分搜索就把元素列表减少一半。因此,如果我们从 32 个元素开始,在第一次不成功的猜测之后,我们将剩下 16 个元素。

所以考虑一个有 8 个元素的数组,在第一次不成功之后,二分搜索会把列表减少一半,留下 4 个元素,然后在第二次不成功的猜测之后留下 2 个元素,最后只剩下 1 个元素,要么是target要么不是,检查还需要一步。因此,总的来说,二分搜索最多需要 4 次猜测才能在一个有 8 个元素的数组中搜索到target

如果列表的大小是 16,那么在第一次不成功的猜测之后,我们会剩下 8 个元素。之后,正如我们所知,我们需要 4 次猜测,加上 1 次猜测,将列表从 16 个减少到 8 个,这样我们就有了 5 次猜测。

所以我们可以说,随着元质数量的增加,找到target所需的猜测数量会增加1

看到模式了吗?

概括起来,我们可以说,对于具有n元素的数组,

我们可以重复减半的次数,从n开始,直到得到值 1,再加 1。

你猜怎么着,在数学中,函数log<sub>2</sub> n的意思完全一样。我们已经看到上面的日志功能是如何工作的,你注意到了吗?

对于n = 8log<sub>2</sub> n的输出结果是3,这意味着数组最大可以减半 3 倍,因此寻找目标值的步数(最多)为(3 + 1) = 4。

问你一个问题:2,097,152 元素列表中搜索一个数字,二分搜索需要的最大猜测次数是多少?

现在我们已经学习了二分搜索算法,您还可以学习其他类型的搜索算法及其应用:

  • 线性搜索
  • 跳转搜索


排序介绍

原文:https://www.studytonight.com/data-structures/introduction-to-sorting

排序只不过是按升序或降序排列数据。随着人类意识到快速搜索的重要性,术语“排序”应运而生。

在我们的现实生活中,有太多的东西需要我们去搜索,比如数据库中的某个特定记录、优点列表中的滚动号码、电话簿中的某个特定电话号码、某本书中的某个特定页面等等。如果数据保持无序和未排序,这一切都将是一团糟,但幸运的是排序的概念出现了,使每个人更容易按顺序排列数据,从而更容易搜索。

排序按顺序排列数据,使搜索更容易。


分拣效率

如果你问我,我将如何按顺序排列一副洗牌的牌,我会说,我将从检查每张牌开始,并在继续前进时制作一副牌。

我可能要花几个小时才能把甲板整理好,但我会这样做。

感谢上帝,电脑不是这样工作的。

自编程时代开始以来,计算机科学家一直致力于通过提出各种不同的算法来排序数据,从而解决排序问题。

判断哪种算法优于另一种算法的两个主要标准是:

  1. 给定数据排序所花费的时间。
  2. 这样做所需的内存空间。

不同的排序算法

根据效率和空间要求的不同,有许多不同的排序技术可供选择。以下是我们将在接下来的几个教程中介绍的一些排序技术。

  1. 冒泡排序
  2. 插入排序
  3. 选择排序
  4. 快速排序
  5. 归并排序
  6. 堆排序

虽然这些排序技巧比较容易理解,但还是建议大家先了解一下空间复杂度、时间复杂度以及搜索算法,为排序算法暖脑。



冒泡排序算法

原文:https://www.studytonight.com/data-structures/bubble-sort

冒泡排序是一种简单的算法,用于对一组给定的n元素进行排序,这些元素以数组的形式提供,具有n个元素。冒泡排序逐个比较所有元素,并根据它们的值对它们进行排序。

如果给定的数组必须按升序排序,那么冒泡排序将从比较数组的第一个元素和第二个元素开始,如果第一个元素大于第二个元素,它将交换两个元素,然后继续比较第二个和第三个元素,以此类推。

如果我们有总共n个元素,那么我们需要重复这个过程n-1次。

它被称为气泡排序,因为随着每一次完整的迭代,给定数组中最大的元素,向最后一个地方或最高的索引冒泡,就像一个水气泡上升到水面一样。

排序是通过逐个遍历所有元素,并将其与相邻元素进行比较,然后在需要时交换它们来进行的。

注意:如果不熟悉数据结构中的排序,首先要学习什么是排序了解排序的基础知识。


实现冒泡排序算法

以下是冒泡排序中涉及的步骤(用于按升序对给定数组进行排序):

  1. 从第一个元素开始(index = 0),将当前元素与数组的下一个元素进行比较。
  2. 如果当前元素大于数组的下一个元素,则交换它们。
  3. 如果当前元素小于下一个元素,则移动到下一个元素。重复步骤 1

让我们考虑一个有值的数组{5, 1, 6, 2, 4, 3}

下面,我们有一个泡泡排序如何排序给定数组的图示。

Bubble sort algorithm

因此,正如我们在上面的表示中所看到的,在第一次迭代之后,6被放置在最后一个索引处,这是它的正确位置。

同样,第二次迭代后,5将位于第二个最后一个索引处,以此类推。

是时候为冒泡排序编写代码了:

// below we have a simple C program for bubble sort
#include <stdio.h>

void bubbleSort(int arr[], int n)
{
    int i, j, temp;
    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n-i-1; j++)
        {
            if( arr[j] > arr[j+1])
            {
                // swap the elements
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            } 
        }
    }

    // print the sorted array
    printf("Sorted Array: ");
    for(i = 0; i < n; i++)
    {
        printf("%d  ", arr[i]);
    }
}

int main()
{
    int arr[100], i, n, step, temp;
    // ask user for number of elements to be sorted
    printf("Enter the number of elements to be sorted: ");
    scanf("%d", &n);
    // input elements if the array
    for(i = 0; i < n; i++)
    {
        printf("Enter element no. %d: ", i+1);
        scanf("%d", &arr[i]);
    }
    // call the function bubbleSort
    bubbleSort(arr, n);

    return 0;
}

虽然上面的逻辑将对未排序的数组进行排序,但是上面的算法仍然是无效的,因为根据上面的逻辑,即使数组在第二次迭代之后被排序,外部for循环也将继续执行 6 迭代。

所以,我们显然可以优化我们的算法。


优化冒泡排序算法

为了优化冒泡排序算法,我们可以引入一个flag来监控元素是否在内部for循环中被交换。

因此,在内部for循环中,我们每次都检查元素交换是否正在进行。

如果对于特定的迭代,没有发生交换,这意味着数组已经被排序,我们可以跳出for循环,而不是执行所有的迭代。

让我们考虑一个有值的数组{11, 17, 18, 26, 23}

下面,我们有一个优化气泡排序如何排序给定数组的图示。

Optimized Bubble sort algorithm

如我们所见,在第一次迭代中,交换发生了,因此我们将flag值更新为1,结果,执行再次进入for循环。但是在第二次迭代中,不会发生交换,因此flag的值将保持0,并且执行将脱离循环。

// below we have a simple C program for bubble sort
#include <stdio.h>

void bubbleSort(int arr[], int n)
{
    int i, j, temp, flag=0;
    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n-i-1; j++)
        {
            // introducing a flag to monitor swapping
            if( arr[j] > arr[j+1])
            {
                // swap the elements
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
                // if swapping happens update flag to 1
                flag = 1;
            } 
        }
        // if value of flag is zero after all the iterations of inner loop
        // then break out
        if(flag==0)
        {
            break;
        }
    }

    // print the sorted array
    printf("Sorted Array: ");
    for(i = 0; i < n; i++)
    {
        printf("%d  ", arr[i]);
    }
}

int main()
{
    int arr[100], i, n, step, temp;
    // ask user for number of elements to be sorted
    printf("Enter the number of elements to be sorted: ");
    scanf("%d", &n);
    // input elements if the array
    for(i = 0; i < n; i++)
    {
        printf("Enter element no. %d: ", i+1);
        scanf("%d", &arr[i]);
    }
    // call the function bubbleSort
    bubbleSort(arr, n);

    return 0;
}

bubble-sort

在上面的代码中,在函数bubbleSort中,如果对于j迭代的单个完整周期(内部for循环),没有发生交换,那么flag将保留0,然后我们将脱离for循环,因为数组已经被排序了。


冒泡排序的复杂度分析

在冒泡排序中,n-1比较将在第一遍中进行,n-2在第二遍中进行,n-3在第三遍中进行,以此类推。所以比较的总数是,

(n-1) + (n-2) + (n-3) +.....+ 3 + 2 + 1 总和= n(n-1)/2 即 O(n 2 )

因此泡泡排序的时间复杂度O(n 2 )

冒泡排序的主要优点是算法简单。

气泡排序的空间复杂度0(1),因为只需要一个额外的内存空间,即temp变量。

此外,最佳案例时间复杂度将是 O(n) ,此时列表已经排序。

以下是气泡排序算法的时间和空间复杂度。

  • 最坏情况时间复杂度【大 O】:O(n2)
  • 最佳案例时间复杂度[大ω]:O(n)
  • 平均时间复杂度【大θ】:O(n2)
  • 空间复杂度: O(1)

既然我们已经学习了气泡排序算法,您也可以查看这些排序算法及其应用:

  • 插入输出
  • 选择排序
  • 快速排序
  • 归并排序
  • 堆排序
  • 计数排序


插入排序算法

原文:https://www.studytonight.com/data-structures/insertion-sorting

假设你手里有一副牌中的 10 张。它们被排序,或者按照数字的升序排列。

如果我再给你一张牌,让你的牌插在刚刚好的位置,这样你手里的牌还能排序。你会怎么做?

嗯,你必须从头到尾检查每张卡,找到新卡的正确位置,将它的价值与每张卡进行比较。一旦你找到正确的位置,你将插入卡片在那里。

同样,如果有更多的新卡提供给你,你可以很容易地重复同样的过程,插入新卡,并保持卡片分类。

这正是插入排序的工作原理。它从索引1(不是0)开始,从索引1开始的每个索引就像一张新卡,你必须把它放在左边排序的子数组的右边位置。

以下是插入排序的一些重要特征:

  1. 它对于较小的数据集是有效的,但是对于较大的列表非常低效。
  2. 插入排序是自适应的,这意味着如果提供部分排序的数组作为输入,它将减少总的步骤数,从而提高效率。
  3. 它优于选择排序和冒泡排序算法。
  4. 其空间复杂度较小。像冒泡排序一样,插入排序也需要一个额外的内存空间。
  5. 这是一种稳定的排序技术,因为它不会改变相等元素的相对顺序。

How stable sort works


插入排序是如何工作的?

以下是插入排序中涉及的步骤:

  1. 我们首先制作给定数组的第二个元素,即索引1处的元素,即key。这里的key元素是我们需要添加到我们现有的分类卡片集中的新卡(记住上面的卡片例子)。
  2. 我们将key元素与其之前的元素进行比较,在本例中,索引0处的元素:
    • 如果key元素小于第一个元素,我们在第一个元素之前插入key元素。
    • 如果key元素大于第一个元素,那么我们把它插在第一个元素之后。
  3. 然后,我们将数组的第三个元素设为key,并将它与它左边的元素进行比较,并将其插入右边的位置。
  4. 我们继续重复这个过程,直到数组被排序。

让我们考虑一个有值的数组{5, 1, 6, 2, 4, 3}

下面,我们有一个泡泡排序如何排序给定数组的图示。

Insertion Sort algorithm pictorial representation

如上图所示,在选择一个key后,我们开始迭代key左边的元素。

如果元素大于key元素,我们继续向左移动,当我们找到小于key元素的元素时,我们停止。

并且,在小于key元素的元素后插入key元素。


实现插入排序算法

下面我们有一个 C++ 语言中插入排序的简单实现。

 #include <stdlib.h>
#include <iostream>

using namespace std;

//member functions declaration
void insertionSort(int arr[], int length);
void printArray(int array[], int size);

// main function
int main() 
{
	int array[5] = {5, 1, 6, 2, 4, 3};
	// calling insertion sort function to sort the array
	insertionSort(array, 6);
	return 0;
}

void insertionSort(int arr[], int length) 
{
	int i, j, key;
	for (i = 1; i < length; i++) 
	{
		j = i;
 		while (j > 0 && arr[j - 1] > arr[j]) 
 		{
 			key = arr[j];
 			arr[j] = arr[j - 1];
 			arr[j - 1] = key;
 			j--;
 		}
	}
	cout << "Sorted Array: ";
	// print the sorted array
	printArray(arr, length);
}

// function to print the given array 
void printArray(int array[], int size)
{ 
 	int j;
	for (j = 0; j < size; j++)
	{
 		cout <

排序数组:1 2 3 4 5 6

现在让我们试着理解上面简单的插入排序算法。

我们取了一个带有 6 整数的数组。我们取了一个变量key,在每次传递过程中,我们将数组的每个元素放入其中,从第二个元素开始,也就是a[1]

然后使用while循环,我们迭代,直到j变得等于或者我们找到一个大于key的元素,然后我们在那个位置插入key

我们继续这样做,直到j变得等于,或者我们遇到比key小的元素,然后我们停止。当前的key现在处于正确的位置。

然后我们将下一个元素设为key,然后重复同样的过程。

在上面的数组中,首先我们选取 1 作为key,我们将其与 5 (元素在 1 之前) 15 小,我们在 5 之前插入 1 。然后我们挑 6 作为key,与 51 进行对比,这次没有换挡到位。然后 2 变成key65 比较,然后 2 插在 1 之后。这一直持续到整个数组被排序。


插入排序的复杂度分析

如上所述,插入排序是一种高效的排序算法,因为它不使用for循环在预设条件下运行,而是使用一个while循环,这避免了数组排序后的额外步骤。

尽管插入排序是有效的,但是如果我们为插入排序算法提供一个已经排序的数组,它仍然会执行外部的for循环,从而需要n步来对已经排序的n元质数组进行排序,这使得它的最佳情况时间复杂度n的线性函数。

最坏情况时间复杂度【大 O】:O(n2)

最佳案例时间复杂度[大ω]:O(n)

平均时间复杂度【大θ】:O(n2)

空间复杂度: O(1)



选择排序算法

原文:https://www.studytonight.com/data-structures/selection-sorting

选择排序是概念上最简单的排序算法。该算法将首先找到数组中最小的元素,并将其与第一位置的元素交换,然后找到第二最小的元素,并将其与第二位置的元素交换,并继续这样做,直到整个数组被排序。

之所以称之为选择排序,是因为它反复地选择下一个最小的元素,并将其交换到正确的位置。


选择排序是如何工作的?

以下是选择排序中涉及的步骤(用于按升序对给定数组进行排序):

  1. 从第一个元素开始,我们搜索数组中最小的元素,并用第一个位置的元素替换它。
  2. 然后我们继续到第二个位置,从索引1开始,直到最后一个索引,寻找子数组中存在的最小元素。
  3. 我们用第二小元素替换原始数组中第第二位置的元素,或者我们可以说是子数组中第一个位置的元素。
  4. 重复这一过程,直到数组完全排序。

让我们考虑一个有值的数组{3, 6, 1, 8, 4, 5}

下面,我们有一个图示来说明选择排序将如何对给定的数组进行排序。

Selection Sort algo implementation

第一个通道中,最小的元素将是1,因此它将被放置在第一个位置。

然后离开第一个元素,从剩余的元素中搜索下一个最小的元素。我们将得到3作为最小的,所以它将被放置在第二个位置。

然后离开13(因为它们在正确的位置),我们将从剩下的元素中搜索下一个最小的元素,并将其放在第三个位置,一直这样做,直到数组被排序。


寻找子数组中的最小元素

在选择排序中,在第一步中,我们寻找数组中最小的元素,并用第一个位置的元素替换它。这似乎是可行的,不是吗?

假设您有一个具有以下值的数组{3, 6, 1, 8, 4, 5}。现在按照选择排序,我们将从第一个元素开始,寻找数组中最小的数字,这就是1,我们将在索引 2中找到它。一旦找到最小的数字,它将与第一个位置的元素交换。

在下一次迭代中,我们将不得不寻找数组中第二小的数字。如何才能找到第二小的数?这个很棘手?

如果你仔细看,我们已经在第一个位置有了最小的数字/元素,这是它的正确位置,我们现在不必移动它到任何地方。所以我们可以说,第一个元素是排序的,但是右边的元素,从索引1开始就没有。

所以,我们现在将寻找子数组中最小的元素,从索引1开始,到最后一个索引。

迷茫?给它时间去适应。

在我们找到第二个最小的元素并用索引1上的元素替换它之后(这是数组中的第二个位置),我们将对数组的前两个位置进行排序。

然后我们再来研究子阵,从现在的索引2开始,再次寻找这个子阵中最小的元素。


实现选择排序算法

在下面的 C 程序中,我们试图把程序分成小函数,这样你就更容易理解哪个部分在做什么。

实现选择排序算法有很多不同的方法,下面是我们喜欢的一种:

// C program implementing Selection Sort
# include <stdio.h>

// function to swap elements at the given index values
void swap(int arr[], int firstIndex, int secondIndex) 
{   
    int temp;
    temp = arr[firstIndex];
    arr[firstIndex] = arr[secondIndex];
    arr[secondIndex] = temp;
}

// function to look for smallest element in the given subarray
int indexOfMinimum(int arr[], int startIndex, int n) 
{
    int minValue = arr[startIndex];
    int minIndex = startIndex;

    for(int i = minIndex + 1; i < n; i++) {
        if(arr[i] < minValue) 
        {
            minIndex = i;
            minValue = arr[i];
        }
    } 
    return minIndex;
}

void selectionSort(int arr[], int n) 
{
    for(int i = 0; i < n; i++) 
    {
        int index = indexOfMinimum(arr, i, n);
        swap(arr, i, index);
    }

}

void printArray(int arr[], int size)
{
    int i;
    for(i = 0; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main()
{
    int arr[] = {46, 52, 21, 22, 11};
    int n = sizeof(arr)/sizeof(arr[0]);
    selectionSort(arr, n);
    printf("Sorted array: \n");
    printArray(arr, n);
    return 0;
}

注意:选择排序是不稳定排序,即排序时可能会改变列表中两个相似元素的出现。但是当使用链表实现时,它也可以作为一个稳定的排序。


选择排序的复杂度分析

Selection Sort 需要两个嵌套的for循环来完成自身,一个for循环在函数selectionSort中,在第一个循环中,我们正在调用另一个函数indexOfMinimum,它有第二个(内部)for循环。

因此,对于给定的输入大小n,选择排序算法的时间和空间复杂度如下:

最坏情况时间复杂度【大 O】:O(n2)

最佳案例时间复杂度[大ω]:O(n2)

平均时间复杂度【大θ】:O(n2)

空间复杂度: O(1)



快速排序算法

原文:https://www.studytonight.com/data-structures/quick-sort

快速排序是不同的排序技术之一,它基于分治的概念,就像归并排序一样。但是在快速排序中,所有繁重的工作(主要工作)都是在数组划分为子数组时完成的,而在归并排序的情况下,所有真正的工作都发生在合并子数组的过程中。在快速排序的情况下,合并步骤完全不起作用。

也叫分区交换排序。该算法将列表分为三个主要部分:

  1. 小于枢轴元素的元素
  2. 枢轴元素(中心元素)
  3. 大于枢轴元素的元素

Pivot 元素可以是数组中的任意元素,可以是第一个元素,最后一个元素,也可以是任意随机元素。在本教程中,我们将最右边的元素或最后一个元素作为

例如:在阵{52, 37, 63, 14, 17, 8, 6, 25}中,我们以25。所以第一遍过后,名单会这样改。

{ 6 8 17 14 25 63 37 52 }

因此,在第一次通过后,枢轴将被设置在其位置,所有元素在其左侧较小,所有元素在其右侧较大。现在6 8 17 1463 37 52被认为是两个独立的 sunarrays,相同的递归逻辑将被应用于它们,我们将继续这样做,直到整个数组被排序。


快速排序的工作原理是什么?

以下是快速排序算法中涉及的步骤:

  1. 在选择一个元素作为之后,这是我们这里数组的最后一个索引,我们第一次划分数组。
  2. 在快速排序中,我们称之为分区。将数组分解为 2 个子数组并不简单,但在划分的情况下,数组元素的位置应使所有小于枢轴的元素位于枢轴的左侧,所有大于枢轴的元素位于枢轴的右侧。
  3. 并且枢轴元件将处于其最终的分类位置。
  4. 左侧和右侧的元素可能没有排序。
  5. 然后我们选取子数组、轴左侧的元素轴右侧的元素,通过选择子数组中的对它们进行分区

让我们考虑一个有值的数组{9, 7, 5, 11, 12, 2, 14, 3, 10, 6}

下面,我们有一个图片表示排序将如何快速排序给定的数组。

How Quick Sort algorithm works

在第一步中,我们选择最后一个元素作为枢轴,在这种情况下是6,并调用partitioning,因此重新排列数组,使得6将被放置在其最终位置,并且在其左侧将有所有小于它的元素,在其右侧,我们将有所有大于它的元素。

然后我们选择左边的子数组和右边的子数组,为它们选择一个枢轴,在上图中,我们选择3作为左边子数组的枢轴,选择11作为右边子数组的枢轴。

我们再次呼吁partitioning


实现快速排序算法

下面我们有一个实现快速排序算法的简单 C 程序:

// simple C program for Quick Sort
#include <stdio.h>
int partition(int a[], int beg, int end);  
void quickSort(int a[], int beg, int end);  
void main()  
{  
    int i;  
    int arr[10]={90,23,101,45,65,28,67,89,34,29};  
    quickSort(arr, 0, 9);  
    printf("\n The sorted array is: \n");  
    for(i=0;i<10;i++)  
    printf(" %d\t", arr[i]);  
}  
int partition(int a[], int beg, int end)  
{  
    int left, right, temp, loc, flag;     
    loc = left = beg;  
    right = end;  
    flag = 0;  
    while(flag != 1)  
    {  
        while((a[loc] <= a[right]) && (loc!=right))  
        right--;  
        if(loc==right)  
        flag =1;  
        else if(a[loc]>a[right])  
        {  
            temp = a[loc];  
            a[loc] = a[right];  
            a[right] = temp;  
            loc = right;  
        }  
        if(flag!=1)  
        {  
            while((a[loc] >= a[left]) && (loc!=left))  
            left++;  
            if(loc==left)  
            flag =1;  
            else if(a[loc] < a[left])  
            {  
                temp = a[loc];  
                a[loc] = a[left];  
                a[left] = temp;  
                loc = left;  
            }  
        }  
    }  
    return loc;  
}  
void quickSort(int a[], int beg, int end)  
{  
    int loc;  
    if(beg<end)  
    {  
        loc = partition(a, beg, end);  
        quickSort(a, beg, loc-1);  
        quickSort(a, loc+1, end);  
    }  
} 

output-quick-sort


快速排序的复杂度分析

对于其中划分导致子数组不平衡的数组,在左侧没有元素,所有元素大于枢轴,因此在右侧。

而如果继续得到不平衡的子阵,那么运行时间就是最坏的情况,也就是O(n<sup>2</sup>)

如果划分导致几乎相等的子阵,那么运行时间最好,时间复杂度为 O(n*log n)

最坏情况时间复杂度【大 O】:O(n2)

最佳案例时间复杂度[大ω]:O(n * log n)

平均时间复杂度[大-θ]:O(n * log n)

空间复杂度: O(n*log n)

我们现在知道,如果分区后产生的子阵分区不平衡,快速排序需要更多的时间才能完成。如果有人知道你一直选择最后一个索引作为枢纽,他们可以故意给你提供数组,这将导致最坏情况下的快速排序运行时间。

为了避免这种情况,您也可以随机选择元素。这在算法上不会有什么区别,因为你所需要做的就是从数组中选择一个随机元素,用最后一个索引处的元素交换它,使它成为枢轴,然后继续快速排序。

  • 快速排序需要的空间很少,只需要O(n*log n)额外空间。
  • 快速排序不是一种稳定的排序技术,因此它可能会在排序时改变列表中两个相似元素的出现。

现在我们已经学习了快速排序算法,您也可以查看这些排序算法及其应用:

  • 插入输出
  • 选择排序
  • 气泡排序
  • 归并排序
  • 堆排序
  • 计数排序


归并排序算法

原文:https://www.studytonight.com/data-structures/merge-sort

归并排序遵循分而治之的规则,递归地对给定的一组数字/元素进行排序,因此耗时更少。

在继续归并排序之前,请先检查以下主题:

  • 选择排序
  • 插入输出
  • 算法的空间复杂度
  • 算法的时间复杂度

在前两个教程中,我们学习了选择排序和插入排序,这两种排序的最坏情况运行时间均为O(n<sup>2</sup>)。随着输入大小的增加,插入和选择排序可能需要很长时间才能运行。

另一方面,归并排序在所有情况下都在O(n*log n)时间内运行。

在继续之前,归并排序如何工作及其实现,首先让我们了解分治的规则是什么?


分治法

如果我们能把单个大问题分解成更小的子问题,解决更小的子问题,并结合它们的解决方案,找到原来大问题的解决方案,那么整个问题就变得更容易解决了。

举个例子分而治之

当英国人来到印度时,他们看到了一个不同宗教和谐相处的国家,勤劳但天真的公民,多样性中的团结,他们发现很难建立自己的帝国。于是,他们采取了分而治之的政策。在印度人口对他们来说是一个大问题的地方,他们通过煽动当地国王之间的竞争,使他们相互对立,将问题分成更小的问题,这对他们来说非常有效。

嗯,那是历史,也是社会政治政策(分而治之),但这里的想法是,如果我们能以某种方式将一个问题分成更小的子问题,最终解决整个问题就变得更容易了。

归并排序中,给定的带有n元素的未排序数组被分成n子数组,每个子数组有一个元素,因为单个元素本身总是被排序的。然后,它重复合并这些子数组,以产生新的排序子数组,最后,产生一个完整的排序数组。

分治的概念包括三个步骤:

  1. 的问题分成多个小问题。
  2. 通过解决子问题来征服。这个想法是将问题分解成原子子问题,在那里它们被实际解决。
  3. 结合子问题的解找到实际问题的解。

Divide and Conquer algorithm


归并排序是如何工作的?

正如我们已经讨论过的,归并排序利用分治规则将问题分解为子问题,在这种情况下的问题是,排序给定的数组

在归并排序中,我们在中途分解给定的数组,例如,如果原始数组有6个元素,那么归并排序将把它分解成两个子数组,每个子数组有3个元素。

但是将原始数组分成两个更小的子数组并不能帮助我们对数组进行排序。

所以我们将这些子数组分解成更小的子数组,直到我们有多个子数组,其中有单元素。现在,这里的想法是,具有单个元素的数组已经被排序了,所以一旦我们将原始数组分解为只有单个元素的子数组,我们就成功地将问题分解为基本问题。

然后我们必须一步一步地合并所有这些排序的子数组,形成一个单一的排序数组。

让我们考虑一个有值的数组{14, 7, 3, 12, 9, 11, 6, 12}

下面,我们有一个图片表示归并排序将如何排序给定的数组。

Working of Merge Sort algorithm

在归并排序中,我们遵循以下步骤:

  1. 我们取一个变量p并将数组的起始索引存储在这里。我们取另一个变量r并将数组的最后一个索引存储在其中。
  2. 然后我们用公式(p + r)/2找到数组的中间,把中间的索引标记为q,把数组分成两个子数组,从pq,从q + 1r索引。
  3. 然后我们再次划分这两个子数组,就像我们划分主数组一样,然后继续。
  4. 一旦我们已经将主数组分成具有单个元素的子数组,那么我们就开始合并子数组。

实现归并排序算法

下面我们有一个实现归并排序算法的 C 程序。

/*  
    a[] is the array, p is starting index, that is 0, 
    and r is the last index of array. 
*/

#include <stdio.h>

// lets take a[5] = {32, 45, 67, 2, 7} as the array to be sorted.

// merge sort function
void mergeSort(int a[], int p, int r)
{
    int q;
    if(p < r)
    {
        q = (p + r) / 2;
        mergeSort(a, p, q);
        mergeSort(a, q+1, r);
        merge(a, p, q, r);
    }
}

// function to merge the subarrays
void merge(int a[], int p, int q, int r)
{
    int b[5];   //same size of a[]
    int i, j, k;
    k = 0;
    i = p;
    j = q + 1;
    while(i <= q && j <= r)
    {
        if(a[i] < a[j])
        {
            b[k++] = a[i++];    // same as b[k]=a[i]; k++; i++;
        }
        else
        {
            b[k++] = a[j++];
        }
    }

    while(i <= q)
    {
        b[k++] = a[i++];
    }

    while(j <= r)
    {
        b[k++] = a[j++];
    }

    for(i=r; i >= p; i--)
    {
        a[i] = b[--k];  // copying back the sorted list to a[]
    } 
}

// function to print the array
void printArray(int a[], int size)
{
    int i;
    for (i=0; i < size; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
}

int main()
{
    int arr[] = {32, 45, 67, 2, 7};
    int len = sizeof(arr)/sizeof(arr[0]);

    printf("Given array: \n");
    printArray(arr, len);

    // calling merge sort
    mergeSort(arr, 0, len - 1);

    printf("\nSorted array: \n");
    printArray(arr, len);
    return 0;
}

给定数组:32 45 67 2 7 排序数组:2 7 32 45 67


归并排序的复杂度分析

归并排序相当快,时间复杂度为O(n*log n)。这也是一种稳定的排序,这意味着“相等”的元素在排序列表中以相同的顺序排序。

在本节中,我们将了解为什么归并排序的运行时间是O(n*log n)

正如我们在二分搜索中已经了解到的,每当我们在每一步中把一个数分成两半时,都可以用对数函数来表示,这就是log n,步数可以用log n + 1来表示(最多)

此外,我们执行单步操作来找出任何子数组的中间,即O(1)

而要合并子数组,通过分割n元素的原始数组而制成,将需要O(n)的运行时间。

因此mergeSort功能的总时间将变为n(log n + 1),这给了我们一个O(n*log n)的时间复杂度。

最坏情况时间复杂度[大 O ]: O(n*log n)

最佳案例时间复杂度[大ω]:O(n * log n)

平均时间复杂度[大-θ]:O(n * log n)

空间复杂度: O(n)

  • 归并排序的时间复杂度在所有 3 种情况下(最差、平均和最佳)都是O(n*Log n),因为归并排序总是数组分成两半,并且需要线性时间来合并两半。
  • 它需要与未排序数组相等的额外空间。因此,它根本不推荐用于搜索大型未排序数组。
  • 这是用于排序链表的最佳排序技术。

现在我们已经学习了插入排序算法,您也可以查看这些其他排序算法及其应用:

  • 气泡排序
  • 插入输出
  • 快速排序
  • 选择排序
  • 堆排序
  • 计数排序


堆排序算法

原文:https://www.studytonight.com/data-structures/heap-sort

堆排序是最好的排序方法之一,并且没有二次最坏情况运行时间。堆排序包括从给定的数组构建一个数据结构,然后利用堆对数组进行排序。

您一定想知道,将数字数组转换为堆数据结构将如何帮助对数组进行排序。为了理解这一点,让我们从理解什么是堆开始。

注意:如果不熟悉数据结构中的排序,首先要学习什么是排序了解排序的基础知识。


什么是堆?

堆是一种特殊的基于树的数据结构,它满足以下特殊的堆属性:

  1. Shape Property: Heap data structure is always a Complete Binary Tree, which means all levels of the tree are fully filled.

    difference between complete and incomplete binary tree

  2. Heap Property: All nodes are either greater than or equal to or less than or equal to each of its children. If the parent nodes are greater than their child nodes, heap is called a Max-Heap, and if the parent nodes are smaller than their child nodes, heap is called Min-Heap.

    Min-Heap and Max-heap


堆排序是如何工作的?

堆排序算法分为两个基本部分:

  • 创建未排序列表/数组的堆。
  • 然后,通过重复从堆中移除最大/最小的元素,并将其插入到数组中,来创建排序数组。每次移除后都会重建堆。

最初在收到未排序的列表时,堆排序的第一步是创建一个堆数据结构(最大堆或最小堆)。一旦构建了堆,堆的第一个元素要么是最大的,要么是最小的(取决于最大堆还是最小堆),所以我们将堆的第一个元素放在数组中。然后我们再次使用剩余的元素创建堆,再次选择堆的第一个元素并将其放入数组。我们不断重复这样做,直到我们的数组中有完整的排序列表。

在下面的算法中,最初调用heapsort()函数,该函数调用heapify()来构建堆。


实现堆排序算法

下面我们有一个实现堆排序算法的简单 C++ 程序。

/*  Below program is written in C++ language  */

#include <iostream>

using namespace std;

void heapify(int arr[], int n, int i)
{
    int largest = i;
    int l = 2*i + 1;
    int r = 2*i + 2;

    // if left child is larger than root
    if (l < n && arr[l] > arr[largest])
        largest = l;

    // if right child is larger than largest so far
    if (r < n && arr[r] > arr[largest])
        largest = r;

    // if largest is not root
    if (largest != i)
    {
        swap(arr[i], arr[largest]);

        // recursively heapify the affected sub-tree
        heapify(arr, n, largest);
    }
}

void heapSort(int arr[], int n)
{
    // build heap (rearrange array)
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // one by one extract an element from heap
    for (int i=n-1; i>=0; i--)
    {
        // move current root to end
        swap(arr[0], arr[i]);

        // call max heapify on the reduced heap
        heapify(arr, i, 0);
    }
}

/* function to print array of size n */
void printArray(int arr[], int n)
{
    for (int i = 0; i < n; i++)
    {
        cout << arr[i] << " ";
    }
    cout << "\n";
}

int main()
{
    int arr[] = {121, 10, 130, 57, 36, 17};
    int n = sizeof(arr)/sizeof(arr[0]);

    heapSort(arr, n);

    cout << "Sorted array is \n";
    printArray(arr, n);
}

堆排序的复杂度分析

最坏情况时间复杂度: O(n*log n)

最佳案例时间复杂度: O(n*log n)

平均时间复杂度: O(n*log n)

空间复杂度: O(1)

  • 堆排序不是稳定排序,对列表排序需要恒定的空间。
  • 堆排序非常快,被广泛用于排序。

现在我们已经学习了堆排序算法,您也可以查看这些排序算法及其应用:

  • 插入输出
  • 选择排序
  • 气泡排序
  • 归并排序
  • 堆排序
  • 计数排序


数据结构

什么是栈数据结构?

原文:https://www.studytonight.com/data-structures/stack-data-structure

是一种抽象数据类型,容量有限(预定义)。这是一种简单的数据结构,允许以特定的顺序添加和移除元素。每次添加一个元素,它都会出现在栈的顶部,唯一可以移除的元素是栈顶部的元素,就像一堆对象一样。

Stack Data Structure


栈的基本特征

  1. 栈是类似数据类型有序列表
  2. 栈是一个后进先出(后进先出)结构,或者我们可以说后进先出(先进先出)。
  3. push()函数用于向栈中插入新元素,pop()函数用于从栈中移除元素。只有称为顶部的堆叠一端允许插入和移除。
  4. 当栈完全满时,称其处于溢出状态;如果栈完全空,称其处于下溢状态。

栈的应用

栈最简单的应用是反转一个单词。你把一个给定的单词一个字母一个字母地推进栈,然后从栈中弹出字母。

还有其他用途也像:

  1. 从语法上分析
  2. 表达式转换(中缀到后缀、后缀到前缀等)

栈数据结构的实现

栈可以使用数组或链表轻松实现。数组很快,但大小有限,链表需要开销来分配、链接、取消链接和解除分配,但大小不受限制。这里我们将使用数组实现栈。

Implementation of Stack


PUSH 运算的算法

  1. 检查栈是否已满。
  2. 如果栈已满,则打印溢出错误并退出程序。
  3. 如果栈未满,则递增顶部并添加元素。

POP 操作的算法

  1. 检查栈是否为空。
  2. 如果栈为空,则打印下溢错误并退出程序。
  3. 如果栈不为空,则在顶部打印元素并递减顶部。

下面我们有一个简单的 C++ 程序来实现栈数据结构,同时遵循面向对象的编程概念。

如果不熟悉 C++ 编程概念,可以从这里学习。

/*  Below program is written in C++ language  */

# include<iostream>

using namespace std;

class Stack
{
    int top;
    public:
    int a[10];  //Maximum size of Stack
    Stack()
    {
        top = -1;
    }

    // declaring all the function
    void push(int x);
    int pop();
    void isEmpty();
};

// function to insert data into stack
void Stack::push(int x)
{
    if(top >= 10)
    {
        cout << "Stack Overflow \n";
    }
    else
    {
        a[++top] = x;
        cout << "Element Inserted \n";
    }
}

// function to remove data from the top of the stack
int Stack::pop()
{
    if(top < 0)
    {
        cout << "Stack Underflow \n";
        return 0;
    }
    else
    {
        int d = a[top--];
        return d;
    }
}

// function to check if stack is empty
void Stack::isEmpty()
{
    if(top < 0)
    {
        cout << "Stack is empty \n";
    }
    else
    {
        cout << "Stack is not empty \n";
    }
}

// main function
int main() {

    Stack s1;
    s1.push(10);
    s1.push(100);
    /*
        preform whatever operation you want on the stack
    */
}

| 顶部位置 | 栈状态 |
| -1 | 栈为空 |
| 0 | 栈中只有一个元素 |
| N-1 | 栈已满 |
| N | 栈溢出状态 |


栈操作分析

下面提到的是可以在栈数据结构上执行的各种操作的时间复杂度。

  • 按压操作:0(1)
  • 弹出操作:0(1)
  • 顶部操作:0(1)
  • 搜索操作 : O(n)

push()pop()函数的时间复杂度是O(1),因为我们总是要从栈的顶部插入或移除数据,这是一个一步到位的过程。

既然我们已经了解了数据结构中的栈,您也可以查看以下主题:

  • 队列数据结构
  • 使用栈排队


什么是队列数据结构?

原文:https://www.studytonight.com/data-structures/queue-data-structure

Queue 也是抽象数据类型或线性数据结构,就像栈数据结构一样,其中第一个元素从称为 REAR (也称为 tail )的一端插入,现有元素的移除发生在称为 FRONT (也称为 head )的另一端。

在继续阅读队列数据结构之前,请先查看以下主题,以便更好地理解它:

  • 数据结构和算法
  • 栈数据结构

这使得队列成为先进先出(先进先出)数据结构,这意味着首先插入的元素将首先被移除。

这正是队列系统在现实世界中的工作方式。如果你去售票处买电影票,排在第一位,那么你将是第一个拿到票的人。正确队列数据结构也是如此。数据先插入,会先离开队列。

将元素添加到队列中的过程称为入队,将元素从队列中移除的过程称为出队

Introduction to Queue


队列的基本特征

  1. 与栈一样,队列也是相似数据类型元素的有序列表。
  2. 队列是先进先出结构。
  3. 一旦新元素被插入到队列中,在队列中新元素之前插入的所有元素都必须被移除,以移除新元素。
  4. peek( )函数通常用于返回第一个元素的值,而不将其出队。

队列的应用

队列,顾名思义,每当我们需要按照这样的顺序管理任何一组对象时都会用到,即第一个进来的对象也先出去,而其他对象等待轮到它们,就像在以下场景中一样:

  1. 在单个共享资源上处理请求,如打印机、中央处理器任务调度等。
  2. 在现实生活中,呼叫中心电话系统使用队列来保持人们按顺序呼叫他们,直到服务代表空闲。
  3. 实时系统中中断的处理。中断的处理顺序与它们到达的顺序相同,即先到先得。

队列数据结构的实现

队列可以使用数组、栈或链表来实现。实现队列最简单的方法是使用数组。

最初队列的(前)和(后)指向数组的第一个索引(从0开始数组的索引)。当我们向队列中添加元素时,尾部继续向前移动,始终指向下一个元素将被插入的位置,而头部保持在第一个索引处。

implementation of queue

当我们从队列中移除一个元素时,我们可以遵循两种可能的方法(上图中提到的[A]和[B])。在[A]方法中,我们在位置移除元素,然后一个接一个地向前移动所有其他元素。

在方法[B]中,我们从位置移除元素,然后将移动到下一个位置。

在方法[A]中,每次我们移除第一个元素时,都有一个将元素向前移动一个位置的开销。

在方法[B]中没有这样的开销,但是每当我们将头向前移动一个位置时,在移除第一个元素后,队列上的大小每次减少一个空间


ENQUEUE 操作的算法

  1. 检查队列是否已满。
  2. 如果队列已满,则打印溢出错误并退出程序。
  3. 如果队列未满,则增加尾部并添加元素。

出列操作的算法

  1. 检查队列是否为空。
  2. 如果队列为空,则打印下溢错误并退出程序。
  3. 如果队列不为空,则在头部打印元素并增加头部。
/* Below program is written in C++ language */

#include<iostream>

using namespace std;

#define SIZE 10

class Queue
{
    int a[SIZE];
    int rear;   //same as tail
    int front;  //same as head

    public:
    Queue()
    {
        rear = front = -1;
    }

    //declaring enqueue, dequeue and display functions
    void enqueue(int x);     
    int dequeue();
    void display();
};

// function enqueue - to add data to queue
void Queue :: enqueue(int x)
{
    if(front == -1) {
        front++;
    }
    if( rear == SIZE-1)
    {
        cout << "Queue is full";
    }
    else
    {
        a[++rear] = x;
    }
}

// function dequeue - to remove data from queue
int Queue :: dequeue()
{
    return a[++front];  // following approach [B], explained above
}

// function to display the queue elements
void Queue :: display()
{
    int i;
    for( i = front; i <= rear; i++)
    {
        cout << a[i] << endl;
    }
}

// the main function
int main()
{
    Queue q;
    q.enqueue(10);
    q.enqueue(100);
    q.enqueue(1000);
    q.enqueue(1001);
    q.enqueue(1002);
    q.dequeue();
    q.enqueue(1003);
    q.dequeue();
    q.dequeue();
    q.enqueue(1004);

    q.display();

    return 0;
}

要实现方法[A],您只需更改dequeue方法,并包含一个for循环,该循环将所有剩余元素移动一个位置。

 return a[0];    //returning first element
for (i = 0; i < tail-1; i++)    //shifting all other elements
{
    a[i] = a[i+1];
    tail--;
}

队列操作的复杂度分析

就像栈一样,在队列的情况下,我们确切地知道新元素将被添加到哪个位置以及从哪里移除元素,因此这两个操作都需要一个步骤。

  • 入队: O(1)
  • 出列: O(1)
  • 尺寸: O(1)


使用栈实现队列

原文:https://www.studytonight.com/data-structures/queue-using-stack

队列由其属性先进先出定义,这意味着先进先出,即先添加的元素先被取出。这种行为定义了一个队列,而数据实际上存储在后台的数组列表中。

我们在这里的意思是,无论数据是如何以及在哪里存储的,如果添加的第一个元素是被移除的第一个元素,并且我们实现了函数enqueue()dequeue()来实现这种行为,我们可以说我们实现了一个队列数据结构。

在我们之前的教程中,我们使用了一个简单的数组来存储数据元素,但是在本教程中,我们将使用栈数据结构来存储数据。

在使用栈实现队列数据结构时,我们还必须考虑栈的自然行为,即先进先出

为了执行入队,我们只需要一个栈,因为我们可以直接数据推到栈上,但是为了执行出队,我们将需要两个栈,因为我们需要遵循队列的先进先出属性,如果我们直接任何数据元素弹出栈,它将遵循后进先出方法。


使用栈实现队列

总之,我们需要两个栈来实现一个队列,我们称它们为S1S2

class Queue {
    public:
    Stack S1, S2;

    //declaring enqueue method
    void enqueue(int x);

    //declaring dequeue method
    int dequeue();
}

在上面的代码中,我们简单地定义了一个类Queue,有两个类型为Stack的变量S1S2

我们知道,Stack 是一种数据结构,其中数据可以使用push()方法添加,数据可以使用pop()方法移除。

您可以在栈数据结构教程中找到Stack类的代码。

要实现队列,我们可以遵循两种方法:

  1. 通过使enqueue操作代价高昂
  2. 通过使dequeue操作代价高昂

1.使得入队操作成本很高

在这种方法中,我们确保添加到队列中最早的元素停留在栈的顶部,其次才是最早的元素,以此类推。

为了实现这一点,我们需要两个栈。将新元素排入队列时,将涉及以下步骤。

注:第一栈(S1)是用来存储数据的主栈,第二栈(S2)是在各种操作中辅助和临时存储数据。

  1. 如果队列为空(表示S1为空),直接第一个元素推送到栈S1上。
  2. 如果队列不为空,则将第一个栈(S1)中的所有元素逐个移动到第二个栈(S2)。然后将新元素添加到第一个栈中,然后将第二个栈中的所有元素移回第一个栈。
  3. 这样做将始终保持栈中元素的正确顺序,第一个数据元素始终位于顶部,第二个数据元素位于其正下方,新的数据元素将被添加到底部。

这使得从队列中移除一个元素变得非常简单,我们所要做的就是调用pop()方法来堆叠S1



2.使得出列操作成本很高

在这种方法中,我们通过简单地调用push()函数向栈S1中插入一个新元素,但是这样做将把我们的第一个元素推向栈的底部,因为我们向栈中插入了更多的元素。

但是我们希望首先移除第一个元素。因此在dequeue操作中,我们将不得不使用第二个栈S2

对于dequeue操作,我们必须遵循以下步骤:

  1. 如果队列是空的(意味着S1是空的),那么我们返回一个错误消息,说队列是空的。
  2. 如果队列不为空,则将第一个栈(S1)中的所有元素逐个移动到第二个栈(S2)。然后从第二个栈中移除顶部的元素,然后将第二个栈中的所有元素移回第一个栈。
  3. 将第一个栈中存在的所有元素移动到第二个栈的目的是颠倒元素的顺序,因为插入队列的第一个元素位于第二个栈的顶部,我们所要做的就是调用第二个栈上的pop()函数来移除该元素。

注: 我们将实施第二种方法,我们将使dequeue()方法代价高昂。


将数据添加到队列- enqueue()

由于我们的队列有一个用于数据存储的栈,而不是数组,因此我们将向栈添加数据,这可以使用push()方法来完成,因此enqueue()方法看起来像:

void Queue :: enqueue(int x) 
{
    S1.push(x);
}

就是这样,新的数据元素被排队并存储在我们的队列中。


从队列中删除数据- dequeue()

当我们说从队列中移除数据时,它总是意味着取出首先插入队列的元素,然后是第二个,以此类推,因为我们必须遵循先进先出方法

但是如果我们简单地在我们的出列方法中执行S1.pop(),那么它将首先移除插入队列中的最后一个元素。那现在怎么办?

Implementing Queue using Stack

如上图所示,我们将第一个栈中存在的所有元素都移动到第二个栈,然后移除顶部元素,之后我们将元素移回第一个栈。

int Queue :: dequeue() 
{
    int x, y;
    while(S1.isEmpty()) 
    {
        // take an element out of first stack
        x = S1.pop();
        // insert it into the second stack
        S2.push();
    }

    // removing the element
    y = S2.pop();

    // moving back the elements to the first stack
    while(!S2.isEmpty()) 
    {
        x = S2.pop();
        S1.push(x);
    }

    return y;
}

现在我们已经知道了enqueue()dequeue()操作的实现,让我们编写一个完整的程序来使用栈实现一个队列。


C++ 中的实现

我们不会遵循使用指针的传统方法,而是定义适当的类,就像我们在栈教程中所做的那样。

/*  Below program is written in C++ language  */

# include<iostream>

using namespace std;

// implementing the stack class
class Stack
{
    int top;
    public:
    int a[10];  //Maximum size of Stack
    Stack()
    {
        top = -1;
    }

    // declaring all the function
    void push(int x);
    int pop();
    bool isEmpty();
};

// function to insert data into stack
void Stack::push(int x)
{
    if(top >= 10)
    {
        cout << "Stack Overflow \n";
    }
    else
    {
        a[++top] = x;
        cout << "Element Inserted into Stack\n";
    }
}

// function to remove data from the top of the stack
int Stack::pop()
{
    if(top < 0)
    {
        cout << "Stack Underflow \n";
        return 0;
    }
    else
    {
        int d = a[top--];
        return d;
    }
}

// function to check if stack is empty
bool Stack::isEmpty()
{
    if(top < 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

// implementing the queue class
class Queue {
    public:
    Stack S1, S2;

    //declaring enqueue method
    void enqueue(int x);

    //declaring dequeue method
    int dequeue();
};

// enqueue function
void Queue :: enqueue(int x) 
{
    S1.push(x);
    cout << "Element Inserted into Queue\n";
}

// dequeue function
int Queue :: dequeue() 
{
    int x, y;
    while(!S1.isEmpty()) 
    {
        // take an element out of first stack
        x = S1.pop();
        // insert it into the second stack
        S2.push(x);
    }

    // removing the element
    y = S2.pop();

    // moving back the elements to the first stack
    while(!S2.isEmpty()) 
    {
        x = S2.pop();
        S1.push(x);
    }

    return y;
}

// main function
int main()
{
    Queue q;
    q.enqueue(10);
    q.enqueue(100);
    q.enqueue(1000);
    cout << "Removing element from queue" << q.dequeue();

    return 0;
}

就这样,我们做到了。



链表介绍

原文:https://www.studytonight.com/data-structures/introduction-to-linked-list

链表是一种非常常用的线性数据结构,由一组节点按顺序组成。

每个节点拥有自己的数据和下一个节点的地址,因此形成了一个链状结构。

链表用于创建树和图形。

Linear Linked List


链表的优点

  • 它们本质上是动态的,在需要时分配内存。
  • 插入和删除操作很容易实现。
  • 栈和队列可以很容易地执行。
  • 链表减少了访问时间。

链表的缺点

  • 内存被浪费了,因为指针需要额外的内存来存储。
  • 没有可以随机访问的元素;它必须顺序访问每个节点。
  • 在链表中反向 t 遍历是困难的。

链表的应用

  • 链表用于实现栈、队列、图形等。
  • 链接列表允许您在列表的开头和结尾插入元素。
  • 在链表中,我们不需要提前知道大小。

链接列表的类型

链表有三种不同的实现,它们是:

  1. 单链表
  2. 双向链表
  3. 循环链表

让我们更多地了解它们,以及它们之间的不同之处。


单链表

单链表包含具有数据部分和地址部分next的节点,该部分指向节点序列中的下一个节点。

我们可以对单链表执行的操作有插入删除遍历

Linear Linked List


双向链表

在双向链表中,每个节点包含一个数据部分和两个地址,一个用于上一个节点,一个用于下一个节点。

Double Linked List


循环链表

在循环链表中,链表的最后一个节点保存第一个节点的地址,从而形成循环链。

Circular Linked List

在接下来的教程中,我们将逐一了解所有 3 种类型的链表。所以点击下一步按钮,让我们了解更多的链表。



线性链表

原文:https://www.studytonight.com/data-structures/linear-linked-list

线性链表是默认的链表和线性数据结构,其中数据不存储在连续的内存位置,但是每个数据节点通过指针连接到下一个数据节点,因此形成一个链。

这种链表中的元素可以通过两种方式插入:

  • 在列表开头插入。
  • 在列表末尾插入。

因此,在编写链表的代码时,我们将在链表的开头和末尾包含向链表插入或添加新数据元素的方法。

我们还将添加一些其他有用的方法,例如:

  • 检查链表是否为空。
  • 搜索链表中的任何数据元素
  • 从列表中删除特定节点(数据元素)

在学习我们如何插入数据和创建链表之前,我们必须了解形成链表的组件,主要组件是节点


什么是节点?

链表中的节点保存数据值和指向链表中下一个节点位置的指针。

Node in linked list

在上图中,我们有一个链表,包含 4 个节点,每个节点都有一些数据(A、B、C 和 D)和一个存储下一个节点位置的指针。

你一定想知道为什么我们需要存储下一个节点的位置。因为分配给这些节点的内存位置不是连续的,所以每个节点应该知道下一个节点存储在哪里。

由于节点是多个信息的组合,因此我们将为Node定义一个类,该类将有一个变量来存储数据和另一个变量来存储指针。在 C 语言中,我们使用struct关键字创建一个结构。

class Node 
{
    public:
    // our linked list will only hold int data
    int data;
    //pointer to the next node
    node* next;

    // default constructor
    Node() 
    {
        data = 0;
        next = NULL;
    }

    // parameterised constructor
    Node(int x) 
    {
        data = x;
        next = NULL;
    }
} 

我们也可以将Node类属性datanext设为私有,那样的话我们就需要添加 getter 和 setter 方法来访问它们(不知道 getter 和 setter 方法是什么:c++ 中的 Inline Functions)。您可以向Node类添加 getter 和 setter 函数,如下所示:

class Node 
{
    // our linked list will only hold int data
    int data;
    //pointer to the next node
    node* next;

    // default constructor same as above

    // parameterised constructor same as above

    /* getters and setters */
    // get the value of data
    int getData() 
    {
        return data;
    }

    // to set the value for data
    void setData(int x) 
    {
        this.data = x;
    }
    // get the value of next pointer
    node* getNext() 
    {
        return next;
    }
    // to set the value for pointer
    void setNext(node *n) 
    {
        this.next = n;
    }
}

Node类基本上为要包含在链表中的数据创建一个节点。一旦类Node的对象被创建,我们使用各种函数将该节点放入链表。


链表类

由于我们遵循完整的 OOPS 方法,因此我们将为链表创建一个单独的类,它将拥有所有的方法,如插入、搜索、删除等。此外,链表类将有一个名为head的指针来存储将被添加到链表中的第一个节点的位置。

 class LinkedList 
{
    public:
    node *head;
    //declaring the functions

    //function to add Node at front
    int addAtFront(node *n);
    //function to check whether Linked list is empty
    int isEmpty();
    //function to add Node at the End of list
    int addAtEnd(node *n);
    //function to search a value
    node* search(int k);
    //function to delete any Node
    node* deleteNode(int x);

    LinkedList() 
    {
        head = NULL;
    }
}

在开头插入

在开头插入节点的步骤:

  1. 第一个节点是任何链表的头部。
  2. 当一个新的链表被实例化时,它只有头,为空。
  3. 否则,头部持有指向列表第一个节点的指针。
  4. 当我们想在前面添加任何节点时,我们必须使头部指向它。
  5. 新添加节点的下一个指针必须指向前一个头,无论它是空的(在新列表的情况下)还是指向列表第一个节点的指针。
  6. 前一个头节点现在是链表的第二个节点,因为新节点被添加在前面。
 int LinkedList :: **addAtFront**(node *n) {
  int i = 0;
  *//making the next of the new Node point to Head*
  n**->**next = head;
  *//making the new Node as Head*
  head = n;
  i++;
  *//returning the position where Node is added*
  return i;
} 

在末尾插入

在末尾插入节点的步骤:

  1. 如果链表是空的,那么我们只需添加新的节点作为链表的头。
  2. 如果链表不是空的,那么我们找到最后一个节点,并使它紧挨着新节点,从而使新节点成为最后一个节点。
 int LinkedList :: **addAtEnd**(node *n) {
  *//If list is empty*
  if(head == NULL) {
    *//making the new Node as Head*
    head = n;
    *//making the next pointe of the new Node as Null*
    n**->**next = NULL;
  }
  else {
    *//getting the last node*
    node *n2 = **getLastNode**();
    n2**->**next = n;
  } 
}

node* LinkedList :: **getLastNode**() {
  *//creating a pointer pointing to Head*
  node* ptr = head;
  *//Iterating over the list till the node whose Next pointer points to null*
  *//Return that node, because that will be the last node.*
  while(ptr**->**next!=NULL) {
    *//if Next is not Null, take the pointer one step forward*
    ptr = ptr**->**next;
  }
  return ptr;
} 

在列表中搜索元素

在搜索中,我们不需要做太多,我们只需要像获取最后一个节点一样遍历,在这种情况下,我们还将比较节点的数据。如果我们得到具有相同数据的节点,我们将返回它,否则我们将使我们的指针指向下一个节点,以此类推。

 node* LinkedList :: **search**(int x) {
  node *ptr = head;
  while(ptr != NULL && ptr**->**data != x) {
    *//until we reach the end or we find a Node with data x, we keep moving*
    ptr = ptr**->**next;
  }
  return ptr;
} 

从列表中删除节点

删除一个节点可以有很多种方式,比如我们先用数据搜索想要删除的节点,然后再删除。在我们的方法中,我们将定义一种方法,该方法将以要删除的数据作为参数,将使用搜索方法来定位它,然后将节点从列表中移除。

要从列表中删除任何节点,我们需要执行以下操作:

  • 如果要删除的节点是第一个节点,那么只需将 Head 的 Next 指针设置为指向要删除的节点的下一个元素。
  • 如果节点在中间的某个地方,那么找到它前面的节点,并使它前面的节点指向它旁边的节点。
 node* LinkedList :: **deleteNode**(int x) {
  *//searching the Node with data x*
  node *n = **search**(x);
  node *ptr = head;
  if(ptr == n) {
    ptr**->**next = n**->**next;
    return n;
  }
  else {
    while(ptr**->**next != n) {
      ptr = ptr**->**next;
    }
    ptr**->**next = n**->**next;
    return n;
  }
} 

检查列表是否为空

我们只需要检查列表的是否为NULL

 int LinkedList :: **isEmpty**() {
  if(head == NULL) {
    return **1**;
  }
  else { return **0**; }
} 

现在你知道了很多关于如何处理列表,如何遍历它,如何搜索一个元素。你可以自己尝试围绕列表编写新方法。

如果你还在想,如何调用所有这些方法,那么下面就是你的main()方法会是什么样子。由于我们遵循了面向对象的标准,我们将创建链接列表类的对象来初始化我们的列表,然后每当我们想要向列表添加任何新节点时,我们将创建节点类的对象。

 int main() {
  LinkedList L;
  *//We will ask value from user, read the value and add the value to our Node*
  int x;
  cout << "Please enter an integer value : ";
  cin >> x;
  Node *n1;
  *//Creating a new node with data as x*
  n1 = new Node(x);
  *//Adding the node to the list*
  L.addAtFront(n1);
} 

同样,您可以调用 LinkedList 类的任何函数,向列表中添加任意数量的节点。



循环链表

原文:https://www.studytonight.com/data-structures/circular-linked-list

循环链表是稍微复杂一点的链接数据结构。在循环链表中,我们可以在链表的任何地方插入元素,而在数组中,我们不能在链表的任何地方插入元素,因为它在连续的内存中。在循环链表中,前一个元素存储下一个元素的地址,最后一个元素存储起始元素的地址。这些元素以环形方式相互指向,形成一条环形链。循环链表具有动态大小,这意味着当需要时可以分配内存。

Circular Linked List

循环链表的应用

  • 使用循环链表的真实应用程序是我们的个人计算机,其中运行着多个应用程序。所有正在运行的应用程序都保存在一个循环链表中,操作系统给所有应用程序一个固定的运行时间。操作系统继续迭代链表,直到所有应用程序都完成。
  • 另一个例子可以是多人游戏。所有玩家都被保存在一个循环链表中,当玩家的机会结束时,指针继续向前移动。
  • 循环链表也可以用来创建循环队列。在队列中,我们必须始终在内存中保留两个指针,前端和后端,而在循环链表中,只需要一个指针。

实现循环链表

实现循环链表非常容易,几乎与线性链表实现相似,唯一的区别是,在循环链表中,最后一个节点将使其下一个指向链表的。在线性链表中,最后一个节点只是在它的下一个指针中保留空值。

这将是我们的节点类,正如我们在本课中已经学习过的,它将用于形成列表。

 class **Node** {
  public:
  int data;
  *//pointer to the next node*
  node* next;

  **node**() {
    data = 0;
    next = NULL;
  }

  **node**(int x) {
    data = x;
    next = NULL;
  }
} 

循环链表

循环链表类将与我们上一课学习的链表类几乎相同,只是在类方法的实现上有一些不同。

 class **CircularLinkedList** {
  public:
  node *head;
  *//declaring the functions*

  *//function to add Node at front*
  int addAtFront(node *n);
  *//function to check whether Linked list is empty*
  int isEmpty();
  *//function to add Node at the End of list*
  int addAtEnd(node *n);
  *//function to search a value*
  node* search(int k);
  *//function to delete any Node*
  node* deleteNode(int x);

  **CircularLinkedList**() {
    head = NULL;
  }
} 

在开头插入

在开头插入节点的步骤:

  1. 第一个节点是任何链表的头部。
  2. 当一个新的链表被实例化时,它只有头,为空。
  3. 否则,头部持有指向列表第一个节点的指针。
  4. 当我们想在前面添加任何节点时,我们必须使头部指向它。
  5. 新添加节点的下一个指针必须指向前一个头,无论它是空的(在新列表的情况下)还是指向列表第一个节点的指针。
  6. 前一个头节点现在是链表的第二个节点,因为新节点被添加在前面。
 int CircularLinkedList :: **addAtFront**(node *n) {
  int i = 0;
  */* If the list is empty */*
  if(head == NULL) {
    n**->**next = head;
    *//making the new Node as Head*
    head = n;
    i++;
  }
  else {
    n->next = head;
    *//get the Last Node and make its next point to new Node*
    Node* last = **getLastNode**();
    last->next = n;
    *//also make the head point to the new first Node*
    head = n;
    i++;
  }
  *//returning the position where Node is added*
  return i;
} 

结尾插入

在末尾插入节点的步骤:

  1. 如果链表是空的,那么我们只需添加新的节点作为链表的头。
  2. 如果链表不是空的,那么我们找到最后一个节点,并使它紧挨着新节点,并使新添加节点的下一个指向链表的头部。
 int CircularLinkedList :: **addAtEnd**(node *n) {
  *//If list is empty*
  if(head == NULL) {
    *//making the new Node as Head*
    head = n;
    *//making the next pointer of the new Node as Null*
    n**->**next = NULL;
  }
  else {
    *//getting the last node*
    node *last = **getLastNode**();
    last**->**next = n;
    *//making the next pointer of new node point to head*
    n**->**next = head;
  } 
} 

在列表中搜索元素

在搜索中,我们不需要做太多,我们只需要像获取最后一个节点一样遍历,在这种情况下,我们还将比较节点的数据。如果我们得到具有相同数据的节点,我们将返回它,否则我们将使我们的指针指向下一个节点,以此类推。

 node* CircularLinkedList :: **search**(int x) {
  node *ptr = head;
  while(ptr != NULL && ptr**->**data != x) {
    *//until we reach the end or we find a Node with data x, we keep moving*
    ptr = ptr**->**next;
  }
  return ptr;
} 

从列表中删除节点

删除一个节点可以有很多种方式,比如我们先用数据搜索想要删除的节点,然后再删除。在我们的方法中,我们将定义一种方法,该方法将以要删除的数据作为参数,将使用搜索方法来定位它,然后将节点从列表中移除。

要从列表中删除任何节点,我们需要执行以下操作:

  • 如果要删除的节点是第一个节点,那么只需将 Head 的 Next 指针设置为指向要删除的节点的下一个元素。并更新最后一个节点的下一个指针。
  • 如果节点在中间的某个地方,那么找到它前面的节点,并使它前面的节点指向它旁边的节点。
  • 如果节点在末尾,则将其移除,并使新的最后一个节点指向头部。
 node* CircularLinkedList :: **deleteNode**(int x) {
  *//searching the Node with data x*
  node *n = **search**(x);
  node *ptr = head;
  **if**(ptr == NULL) {
    cout << "List is empty";
    return NULL;
  }
  **else if**(ptr == n) {
    ptr**->**next = n**->**next;
    return n;
  }
  **else** {
    while(ptr**->**next != n) {
      ptr = ptr**->**next;
    }
    ptr**->**next = n**->**next;
    return n;
  }
} 


双端队列

原文:https://www.studytonight.com/data-structures/double-ended-queue

双端队列是一种更通用的队列数据结构形式,它允许从两端(即前端和后端)插入和移除元素。

Double Ended Queue


双端队列的实现

这里我们将使用循环数组实现一个双端队列。它将有以下方法:

  • 推回:在后面插入元素
  • 向前推:在前面插入元素
  • 弹回:移除最后一个元素
  • pop_front : 移除第一个元素
  • get_back : 返回最后一个元素
  • get_front : 返回第一个元素
  • 空:如果队列为空,则返回真
  • 已满:如果队列已满,则返回真
// Maximum size of array or Dequeue

#define SIZE 5

class Dequeue
{
    //front and rear to store the head and tail pointers
    int  *arr;
    int front, rear;  

    public :

    Dequeue()
    {
    	//Create the array
        arr = new int[SIZE];

        //Initialize front and rear with -1
        front = -1;
        rear = -1;
    }

    // Operations on Deque
    void  push_front(int );
    void  push_back(int );
    void  pop_front();
    void  pop_back();
    int  get_front();
    int  get_back();
    bool  full();
    bool  empty();   
};

在前面插入元素

首先,我们检查队列是否已满。如果没有满,我们按照给定的条件在前端插入一个元素:

  • 如果队列是空的,那么将前面和后面初始化为 0。两者都指向第一个元素。

Double Ended Queue

  • 否则,我们减少前端并插入元素。因为我们使用的是圆形数组,所以我们必须记住,如果 front 等于 0,那么我们不是将它减 1,而是使它等于 SIZE-1。

Double Ended Queue

void Dequeue :: push_front(int key)
{
    if(full())
    {
        cout << "OVERFLOW\n";
    }
    else
    {
    	//If queue is empty
    	if(front == -1)
    		front = rear = 0;

    	//If front points to the first position element 
        else if(front == 0)
            front = SIZE-1;

        else
        	--front;

        arr[front] = key;
    }
}

在后面插入元素

我们再次检查队列是否已满。如果它不是满的,我们按照给定的条件在后面插入一个元素:

  • 如果队列是空的,那么将前面和后面初始化为 0。两者都指向第一个元素。
  • 否则我们增加后部并插入元素。因为我们使用的是圆形数组,所以我们必须记住,如果 rear 等于 SIZE-1,那么我们将使它等于 0,而不是增加 1。

Double Ended Queue

void Dequeue :: push_back(int key)
{
    if(full())
    {
        cout << "OVERFLOW\n";
    }
    else
    {
        //If queue is empty
    	   if(front == -1)
    		  front = rear = 0;

    	   //If rear points to the last element
        else if(rear == SIZE-1)
            rear = 0;

        else
        	++rear;

        arr[rear] = key;
    }    
}

删除第一个元素

为此,我们首先检查队列是否为空。如果不是,则按照给定的条件删除前面的元素:

  • 如果只有一个元素存在,我们再一次使前后等于-1。
  • 否则我们增加战线。但是我们必须记住,如果 front 等于 SIZE-1,那么我们不是将它增加 1,而是使它等于 0。

Double Ended Queue

void Dequeue :: pop_front()
{
    if(empty())
    {
        cout << "UNDERFLOW\n";
    }
    else
    {
    	//If only one element is present
        if(front == rear)
        	front = rear = -1;

        //If front points to the last element 
        else if(front == SIZE-1)
        	front = 0;

        else
        	++front;		
    }
}

删除最后一个元素

为了做到这一点,我们再次首先检查队列是否为空。如果不是,那么我们按照给定的条件删除最后一个元素:

  • 如果只有一个元素存在,我们就使前后等于-1。
  • 否则我们减少后方。但是我们必须记住,如果后方等于 0,那么我们不是将其减少 1,而是使其等于大小-1。

Double Ended Queue

void Dequeue :: pop_back()
{
    if(empty())
    {
        cout << "UNDERFLOW\n";
    }
    else
    {
    	//If only one element is present
        if(front == rear)
        	front = rear = -1;

        //If rear points to the first position element 
        else if(rear == 0)
        	rear = SIZE-1;

        else
        	--rear;		
    }
}

检查队列是否为空

它可以简单地通过查看前面指向的位置来检查。如果 front 仍以-1 开头,则队列为空。

bool Dequeue :: empty()
{
    if(front == -1)
    	return true;
    else
    	return false;
}

检查队列是否已满

因为我们使用的是循环数组,所以我们检查以下条件,如代码所示,以检查队列是否已满。

bool Dequeue :: full()
{
    if((front == 0 && rear == SIZE-1)  ||
    	(front == rear + 1))
        return true;
    else
        return false;
}

返回第一个元素

如果队列不是空的,那么我们只需返回存储在前面指向的位置的值。

int Dequeue :: get_front()
{
    if(empty())
    {	cout << "f=" <<front << endl;
        cout << "UNDERFLOW\n";
        return -1;
    }
    else
    {
        return arr[front];
    }
}

返回最后一个元素

如果队列不是空的,那么我们只需返回存储在后点位置的值。

int Dequeue :: get_back()
{
    if(empty())
    {
        cout << "UNDERFLOW\n";
        return -1;
    }
    else
    {
        return arr[rear];
    }
}


使用队列实现栈

原文:https://www.studytonight.com/data-structures/stack-using-queue

栈是后进先出(LIFO) 结构,即栈中最后添加的元素先取出。我们的目标是实现一个使用队列的栈,该栈将使用两个队列,并以这样的方式设计它们:弹出操作与出列相同,但是推送操作将有点复杂并且更昂贵。


使用队列实现栈

假设我们已经为 Queue 实现了一个类,我们首先为 Stack 设计这个类。它将有方法push()pop()以及两个队列。

class Stack
{
	public:
	// two queue
	Queue Q1, Q2;
	// push method to add data element
	void push(int);
	// pop method to remove data element
	void pop();
};

在栈中插入数据

由于我们使用的队列是先进先出(FIFO) 结构,即先添加的元素先取出,所以我们将执行推送操作,这样每当有弹出操作时,栈总是弹出最后添加的元素。

为此,我们需要两个队列,Q1Q2。每当调用操作时,我们将把Q1的所有元素入队(在这种情况下是移动)到Q2,然后把新元素入队到Q1。在此之后,我们将所有元素从Q2排队(在这种情况下移动)回到Q1

Stack using Queue

让我们在代码中实现它,

void Stack :: push(int x)
{
	// move all elements in Q1 to Q2
	while(!Q1.isEmpty())
	{
		int temp = Q1.deque();
		Q2.enque(temp);
	}

	// add the element which is pushed into Stack
	Q1.enque(x);

	// move back all elements back to Q1 from Q2
	while(!Q2.isEmpty())
	{
		int temp = Q2.deque();
		Q1.enque(temp);
	}
}

你现在一定很清楚,为什么我们使用两个队列。实际上队列Q2只是为了在执行操作时暂时保存数据。

这样我们就可以保证每当调用 pop 操作时,栈总是会弹出Q1队列中添加的最后一个元素。


从栈中删除数据

就像我们上面讨论的,我们只需要对我们的队列Q1使用出列操作。这将为我们提供栈中添加的最后一个元素。

int Stack :: pop()
{
	return Q1.deque();
}

时间复杂度分析

当我们使用队列实现栈时,操作变得昂贵。

  • 推送操作:0(n)
  • 弹出操作:0(1)

结论

当我们说“使用队列实现栈”时,我们指的是如何让队列表现得像一个栈,毕竟它们都是逻辑实体。所以任何数据结构作为一个 Stack,都应该有push()方法在顶部添加数据,有pop()方法从顶部移除数据。这正是我们所做的,并因此实现了让一个队列(在本例中是两个队列)表现为一个栈。



使用链表实现栈

原文:https://www.studytonight.com/data-structures/stack-using-linked-list

我们所知道的栈是一种后进先出(LIFO) 数据结构。它具有以下操作:

  • 推入:将元素推入栈
  • 弹出:移除最后添加的元素
  • top: 返回栈顶部的元素

Stack using Linked List


使用链表实现栈

使用链表可以很容易地实现栈。栈是一种数据结构,可以使用push()方法向其中添加数据,也可以使用pop()方法从其中移除数据。有了链表,操作可以用链表的addAtFront()方法代替,弹出操作可以用删除链表前节点的函数代替。

通过这种方式,我们的链表将虚拟地变成一个具有push()pop()方法的栈。

首先我们创建一个类节点。这是我们的链表节点类,其中将有数据和一个节点指针来存储下一个节点元素的地址。

class node
{
	int data;
	node *next;
};

然后我们定义栈类,

class Stack
{
	node *front;  // points to the head of list
	public:
	Stack()
	{
		front = NULL;
	}
	// push method to add data element
	void push(int);
	// pop method to remove data element
	void pop();
	// top method to return top data element
	int top();
};

在栈中插入数据(链表)

为了将一个元素插入到栈中,我们将创建一个节点并将其放在列表的前面。

void Stack :: push(int d)
{
	// creating a new node
	node *temp;
	temp = new node();
	// setting data to it
	temp->data = d;

	// add the node in front of list
	if(front == NULL)
	{
		temp->next = NULL;
	}
	else
	{
		temp->next = front;
	}
	front = temp;
}

现在,每当我们调用push()函数时,一个新的节点就会被添加到前面的列表中,这就是栈的行为。


从栈中移除元素(链接列表)

为了做到这一点,我们将简单地删除第一个节点,并使第二个节点成为列表的头部。

void Stack :: pop()
{
	// if empty
	if(front == NULL)
		cout << "UNDERFLOW\n";

	// delete the first element
	else
	{
		node *temp = front;
		front = front->next;
		delete(temp);
	}
}

返回栈顶部(链表)

在这种情况下,我们只需返回存储在列表头部的数据。

int Stack :: top()
{
	return front->data;
}

结论

当我们说“使用链表实现栈”时,我们指的是如何让链表表现得像一个栈,毕竟它们都是逻辑实体。所以任何数据结构作为一个 Stack,都应该有push()方法在顶部添加数据,有pop()方法从顶部移除数据。这正是我们所做的,并因此实现了使链表表现为栈。



双向链表

原文:https://www.studytonight.com/data-structures/doubly-linked-list

双向链表是一种类型的链表,其中每个节点除了存储其数据之外还有两个链接。第一个链接指向列表中的上一个节点,第二个链接指向列表中的下一个节点。列表的第一个节点的前一个链接指向空。同样,列表的最后一个节点的下一个节点指向空。

Double Linked List

这两个链接帮助我们向前和向后遍历列表。但是存储一个额外的链接需要一些额外的空间。


双链表的实现

首先我们定义节点。

struct node
{
	int data;     	// Data
	node *prev;  	// A reference to the previous node
	node *next; 	// A reference to the next node
};

现在我们定义我们的类双链表。它有以下方法:

  • add_front: 在列表开头增加一个新节点
  • add_after: 在另一个节点后添加一个新节点
  • add_before: 在另一个节点之前添加一个新节点
  • add_end: 在列表末尾添加新节点
  • 删除:删除节点
  • 正向遍历:正向遍历列表
  • 向后遍历:向后遍历列表
class Doubly_Linked_List
{
	node *front;  	// points to first node of list
	node *end;   	// points to first las of list
	public:
	Doubly_Linked_List()
	{
		front = NULL;
		end = NULL;
	}
	void add_front(int );
	void add_after(node* , int );
	void add_before(node* , int );
	void add_end(int );
	void delete_node(node*);
	void forward_traverse();
	void backward_traverse();
};

在开头插入数据

  1. 第一个节点的 prev 指针将始终为空,下一个的将指向前方
  2. 如果插入的节点是列表的第一个节点,那么我们让前面的末端的指向这个节点。
  3. 否则我们只让前面的指向这个节点。

Double Linked List

void Doubly_Linked_List :: add_front(int d)
{
	// Creating new node
	node *temp;
	temp = new node();
	temp->data = d;
	temp->prev = NULL;
	temp->next = front;

	// List is empty
	if(front == NULL)
		end = temp;

	else
		front->prev = temp;

	front = temp;
}

在节点前插入数据

假设我们在 Y 之前插入节点 X,那么 X 的下一个指针将指向 Y,X 的上一个指针将指向 Y 的上一个指针所指向的节点。Y 的上一个指针现在指向 X。我们需要确保如果 Y 是列表的第一个节点,那么在添加 X 之后,我们会指向 X

Double Linked List

void Doubly_Linked_List :: add_before(node *n, int d)
{
	node *temp;
	temp = new node();
	temp->data = d;
	temp->next = n;
	temp->prev = n->prev;
	n->prev = temp;

	//if node is to be inserted before first node
	if(n->prev == NULL)
		front = temp;
} 

在节点后插入数据

假设我们在 X 之后插入节点 Y,那么 Y 的上一个指针将指向 X,Y 的下一个指针将指向节点 X 的下一个指针。现在,X 的下一个指针将指向 Y。我们需要确保如果 X 是列表的最后一个节点,那么在添加 Y 之后,我们将结束点指向 Y

void Doubly_Linked_List :: add_after(node *n, int d)
{
	node *temp;
	temp = new node();
	temp->data = d;
	temp->prev = n;
	temp->next = n->next;
	n->next = temp;

	//if node is to be inserted after last node
	if(n->next == NULL)
		end = temp;
}

在末尾插入数据

  1. 最后一个节点的下一个指针将始终为空,上一个将指向结束。
  2. 如果插入的节点是列表的第一个节点,那么我们将前端和末端指向这个节点。
  3. 否则我们只对这个节点进行终结。

Double Linked List

void Doubly_Linked_List :: add_end(int d)
{
	// create new node
	node *temp;
	temp = new node();
	temp->data = d;
	temp->prev = end;
	temp->next = NULL;

	// if list is empty
	if(end == NULL)
		front = temp;
	else
		end->next = temp;	
	end = temp;
}

移除节点

在双向链表中删除节点非常容易,但是如果要删除的节点是链表的第一个或最后一个元素,则需要特殊处理。与我们需要前一个节点的单链表不同,这里只需要被删除的节点。我们只需使上一个节点的下一个指向当前节点(要删除的节点)的下一个,下一个节点的上一个指向当前节点的上一个。更多细节请查看代码。

Double Linked List

void Doubly_Linked_List :: delete_node(node *n)
{	
	// if node to be deleted is first node of list
	if(n->prev == NULL)
	{
		front = n->next; //the next node will be front of list
		front->prev = NULL;
	}
	// if node to be deleted is last node of list
	else if(n->next == NULL)
	{
		end = n->prev;   // the previous node will be last of list
		end->next = NULL;
	}
	else
	{
		//previous node's next will point to current node's next
		n->prev->next = n->next;
		//next node's prev will point to current node's prev
		n->next->prev = n->prev;
	}
	//delete node
	delete(n);			
}

向前遍历

从前面的节点开始,访问所有节点,直到该节点变为空。

void Doubly_Linked_List :: forward_traverse()
{
	node *trav;
	trav = front;
	while(trav != NULL)
	{
		cout<<trav->data<<endl;
		trav = trav->next;
	}
}

向后遍历

从结束节点开始,访问所有节点,直到该节点变为空。

void Doubly_Linked_List :: backward_traverse()
{
	node *trav;
	trav = end;
	while(trav != NULL)
	{
		cout<<trav->data<<endl;
		trav = trav->prev;
	}
}

现在我们已经了解了双向链表,您还可以查看其他类型的链表:

  • 线性链表
  • 循环链表


二叉树介绍

原文:https://www.studytonight.com/data-structures/introduction-to-binary-trees

二叉树是一种分层数据结构,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。

每个节点包含三个组件:

  1. 指向左子树的指针
  2. 指向右子树的指针
  3. 数据元素

树中最顶端的节点称为根。空树由指针表示。

二叉树的表示如下所示:

Binary Trees


二叉树:常用术语

  • 根:树中最顶端的节点。
  • 父节点:树中的每个节点(不包括根)都由恰好来自另一个节点的有向边连接。这个节点称为父节点。
  • 子节点:当远离根节点时,直接连接到另一个节点的节点。
  • 叶/外部节点:没有子节点的节点。
  • 内部节点:至少有一个子节点的节点。
  • 节点深度:从根到节点的边数。
  • 节点高度:从节点到最深叶的边数。树的高度就是根的高度。

Binary Trees

在上面的二叉树中我们看到根节点是 A 。该树有 10 个节点,5 个内部节点,即 A、B、C、E、G ,5 个外部节点,即 D、F、H、I、J 。这棵树的高度是 3。 BDE 的父母,而 DEB 的子女。


树木的优势

树木之所以如此有用和频繁使用,是因为它们有一些非常重要的优势:

  • 树反映了数据中的结构关系。
  • 树用于表示层次结构。
  • 树提供了有效的插入和搜索。
  • 树是非常灵活的数据,允许以最小的努力移动子树。

二叉树的类型(基于结构)

  • 有根二叉树:它有一个根节点,每个节点有两个子节点。

  • Full binary tree: It is a tree in which every node in the tree has either 0 or 2 children.

    Binary Trees

    • 完整二叉树中的节点数 n 至少为 n = 2h–1,atmatn = 2h+1–1,其中 h 为树的高度。
    • 全二叉树中叶节点 l 的个数为内部节点+ 1 的 L ,即 l = L+1
  • Perfect binary tree: It is a binary tree in which all interior nodes have two children and all leaves have the same depth or same level.

    Binary Trees

    • l 叶子的完美二叉树有 n = 2l-1 个节点。
    • 在完全二叉树中, l = 2hn = 2h+1 - 1 ,其中, n 为节点数, h 为树高, l 为叶节点数
  • Complete binary tree: It is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.

    Binary Trees

    • n 个节点的完全二叉树内部节点数为层(n/2)
  • Balanced binary tree: A binary tree is height balanced if it satisfies the following constraints:

    1. 左右子树的高度最多相差一,与
    2. 左边的子树是平衡的,与
    3. 右边的子树是平衡的

    一棵空树是高度平衡的。

    Binary Trees

    • 平衡二叉树的高度为 0(Log n),其中 n 为节点数。
  • Degenarate tree: It is a tree is where each parent node has only one child node. It behaves like a linked list.

    Binary Trees



二叉查找树

原文:https://www.studytonight.com/data-structures/binary-search-tree

二叉查找树是一种用于快速添加和删除数据的有用数据结构。

它由存储数据的节点组成,还链接到最多两个其他子节点。正是链接到的叶子和链接叶子(也称为父节点)之间的关系,使得二叉树成为如此高效的数据结构。

对于要成为二叉查找树的二叉树,根节点的左子树中所有节点的数据应该小于根的数据。根节点右子树中所有节点的数据应该大于等于根的数据。因此,树最左边的叶子具有最低值,而树右边的叶子具有最大值。

二叉查找树的代表如下所示:

Binary Search Tree

考虑根节点 20。子树(10,5)左边的所有元素都小于 20,子树(25,30,35)右边的所有元素都大于 20。


BST 的实现

首先,定义一个结构为tree_node。它将存储数据和指向左右子树的指针。

struct tree_node
{
	int data;
	tree_node *left, *right;
}; 

节点本身非常类似于链表中的节点。链表代码的基本知识将对理解二叉树的技术非常有帮助。

最合理的做法是创建一个二叉查找树类,将树的工作封装到一个区域中,并使其可重用。该类将包含向树中插入数据、搜索数据是否存在的函数以及遍历树的方法。

class BST
{
	tree_node *root;
	void insert(tree_node* , int );
	bool search(int , tree_node* );
	void inorder(tree_node* );
	void preorder(tree_node* );
	void postorder(tree_node* );

	public:
	BST()
	{
		root = NULL;
	}
	void insert(int );
	bool search(int key);
    void inorder();
    void preorder();
    void postorder();
}; 

有必要将根初始化为空,以便后面的函数能够识别它不存在。

该类的所有公共成员都被设计为允许该类的用户使用该类,而无需处理底层设计。递归调用的函数是私有的,允许它们沿着树向下移动。


插入到 BST 中

将数据插入到二叉树中涉及到一个函数,该函数在树中插入键值的适当位置搜索一个未使用的节点。插入函数通常是一个递归函数,它在二叉树的层次上继续向下移动,直到某个位置有一个未使用的叶子,这个位置遵循以下放置节点的规则。

  • 比较要插入的根节点和元素的数据。
  • 如果根节点的数据更大,并且如果存在左子树,那么重复步骤 1,其中根=左子树的根。否则,
  • 插入元素作为当前根的左子元素。
  • 如果根节点的数据更大,并且如果存在右子树,那么重复步骤 1,其中根=右子树的根
  • 否则,插入元素作为当前根的右子元素。

Binary Search Tree

void BST :: insert(tree_node *node, int d)
{
	// element to be inserted is lesser than node’s data
	if(d < node->data)
	{
		// if left subtree is present
		if(node->left != NULL)
			insert(node->left, d);

		// create new node
		else
		{
			node->left = new tree_node;
			node->left->data = d;
			node->left->left = NULL;
			node->left->right = NULL;
		}
	}

	// element to be inserted is greater than node’s data
	else if(d >= node->data)
	{
		// if left subtree is present
		if(node->right != NULL)
			insert(node->right, d);

		// create new node
		else
		{
			node->right = new tree_node;
			node->right->data = d;
			node->right->left = NULL;
			node->right->right = NULL;
		}
	}

} 

由于根节点是私有成员,我们还编写了一个公共成员函数,该函数对类的非成员可用。它调用私有递归函数来插入元素,并处理根节点为空的情况。

void BST::insert(int d)
{
	if(root!=NULL)
                insert(root, d);
	else
    {
        root = new tree_node;
        root->data = d;
        root->left = NULL;
        root->right = NULL;
    }
} 

在英国标准时间搜索

搜索功能的工作方式与 insert 类似。它将检查当前节点的键值是否是要搜索的值。如果不是,它应该检查要搜索的值是否小于节点的值,在这种情况下,它应该在左边的子节点上递归调用,或者如果它大于节点的值,它应该在右边的子节点上递归调用。

  • 比较根节点的数据和要搜索的值。
  • 如果根节点的数据更大,并且如果存在左子树,那么重复步骤 1,其中根=左子树的根。否则,
  • 如果根节点的数据更大,并且如果存在右子树,那么重复步骤 1,其中根=右子树的根。否则,
  • 如果要搜索的值等于根节点的数据,则返回 true。
  • 否则,返回 false。
bool BST::search(int d, tree_node *node)
{
	bool ans = false;

	// node is not present
  	if(node == NULL)
 		return false;

	// Node’s data is equal to value searched
    if(d == node->data)
      	return true;

	// Node’s data is greater than value searched
    else if(d < node->data)
       	ans = search(d, node->left);

	// Node’s data is lesser than value searched
    else
       	ans = search(d, node->right);

    return ans;
} 

由于根节点是私有成员,我们还编写了一个公共成员函数,该函数对类的非成员可用。它调用私有递归函数来搜索元素,并处理根节点为空的情况。

bool BST::search(int d)
{
	if(root ==  NULL)
		return false;
	else	
		return  search(d, root);
} 

在基站中穿越

主要有三种类型的树遍历:

1.有序遍历:

在这种技术中,我们执行以下操作:

  • 处理根节点的数据。
  • 首先,完全遍历左子树。
  • 然后,遍历右子树。
void BST :: preorder(tree_node *node)
{
	if(node !=  NULL)
    {
		cout<<node->data<<endl;
       	preorder(node->left);
       	preorder(node->right);
    }
} 

2.后序遍历

在这个遍历技术中,我们执行以下操作:

  • 首先完全遍历左子树。
  • 然后,完全遍历右子树。
  • 然后,处理节点的数据。
void BST :: postorder(tree_node *node)
{
	if(node !=  NULL)
   	{
        postorder(node->left);
        postorder(node->right);
	    cout<<node->data<<endl;
   	}
} 

3.有序遍历

在有序遍历中,我们执行以下操作:

  • 第一个进程左子树。
  • 然后,处理当前根节点。
  • 然后,处理右子树。
void BST :: inorder(tree_node *node)
{
	if(node !=  NULL)
   	{
        inorder(node->left);
	    cout<<node->data<<endl;
        inorder(node->right);
   	}
} 

二叉查找树的有序遍历给出了二叉查找树中存在的数据元素的排序。这是二叉查找树的重要财产。

因为根节点是私有成员,所以我们还编写了公共成员函数,非类成员也可以使用。它调用私有递归函数遍历树,并处理根节点为空的情况。

void BST :: preorder()
{
	if(root ==  NULL)
		cout<<"TREE IS  EMPTY\n";
	else
       	preorder(root);
}

void BST :: postorder()
{
	if(root ==  NULL)
		cout<<"TREE IS  EMPTY\n";
	else
	    postorder(root);
}

void BST :: inorder()
{
	if(root == NULL)
		cout<<"TREE IS EMPTY\n";
	else
		inorder(root);
} 

复杂度分析

Binary Search Tree

搜索和插入的时间复杂度取决于树的高度。平均来说,有 n 个节点的二分搜索树有 O(log n) 的高度。然而,在最坏的情况下,当不平衡的树类似于链表时,树的高度可以是0(n)。例如,在这种情况下:

Binary Search Tree

遍历需要 O(n) 时间,因为每个节点都必须被访问。



贪心算法或技巧

原文:https://www.studytonight.com/data-structures/greedy-algorithm

顾名思义,这是一种简单的方法,试图在每一步找到最佳解。因此,它的目标是在每一步找到局部最优解,从而找到整个问题的全局最优解。

考虑有一个目标函数需要优化(最大化/最小化)。这种方法在每一步都做出贪心的选择,并确保目标函数得到优化。

贪心算法只有一次机会来计算最优解,因此,不能回头查看其他替代解决方案。然而,在许多问题中,这种策略不能产生全局最优解。让我们考虑下面的二叉树来理解基本的贪心算法是如何工作的:

Binary tree

对于上述问题,目标函数是:

寻找和最大的路径。

因为我们需要最大化目标函数,所以可以使用贪心方法。遵循以下步骤找到解决方案:

步骤 1 :初始化总和= 0

第二步:选择根节点,将其值加到sum总和= 0+8 = 8

第三步:算法比较下一级节点,选择最大的节点为 12 ,使得之和= 20

第 4 步:算法比较下一级节点,选择最大的节点为 10 ,使之和= 30

因此,使用贪心算法,我们得到 8-12-10 作为路径。但这不是最优解,因为路径 8-2-89 的总和最大,即 99

出现这种情况是因为算法基于每一步可用的信息做出决策,而不考虑整体问题。


什么时候使用贪心算法?

对于具有以下属性的问题,我们可以使用贪心技术:

  • 贪心选择属性:表示通过局部最优选择可以得到全局最优解。

  • 最优子问题:该属性表示问题的最优解包含子问题的最优解。因此,全局最优解可以由局部最优子解构造。

一般来说,优化问题,或者是我们必须找到某个事物的最大值或最小值或者我们必须找到某个最优解的问题,都是使用贪心技术。

优化问题有两种解决方案:

  • 可行解:这可以被称为满足目标函数的近似解(解的子集),它可以或不可以建立到最优解。

  • 最优解:这可以定义为目标函数最大化或最小化的可行解。


贪心算法中使用的关键术语

  • 目标函数:这个可以定义为需要最大化或者最小化的函数。

  • 候选集:从这个集合中创建全局最优解。

  • 选择功能:确定最佳候选,并将其包含在解集中。

  • 可行性功能:判断一个候选人是否可行,是否能够为解决方案做出贡献。


标准贪心算法

该算法一步一步地进行,每一步考虑一个输入,比如x

  • 如果x给出了一个局部最优解(x是可行的),那么它就包含在部分解集中,否则就被丢弃。
  • 然后算法进入下一步,不再考虑x
  • 这一直持续到输入集完成或找到最优解。

上述算法可以翻译成以下伪代码:

Algorithm Greedy(a, n)   // n defines the input set
{
    solution= NULL;		// initialize solution set
	for i=1 to n do
	{
		x = Select(a);	// Selection Function
		if Feasible(solution, x) then 	// Feasibility solution
			solution = Union (solution, x);   // Include x in the solution set
	}
	return solution;
}


贪心方法/技术的优势

  • 这种技术易于制定和实施。
  • 它在许多场景下都能高效工作。
  • 这种方法最大限度地减少了生成解决方案所需的时间。

现在,让我们也看看一些缺点,

贪心方法/技术的缺点

  • 这种方法不能保证全局最优解,因为它从不回顾为寻找局部最优解所做的选择。

虽然我们已经讨论了一般情况下哪种类型的问题可以使用贪心方法来解决,但是下面是一些使用贪心技术的常见问题:

  1. 背包问题
  2. 活动选择问题
  3. 迪克斯特拉问题
  4. 寻找最小生成树的 Prim 算法
  5. 克鲁斯卡尔最小生成树算法
  6. 霍夫曼编码
  7. 旅行推销员问题

结论

贪心技术最适合以下应用:

  • 需要实时解决方案。
  • 近似解就足够了。


活动选择问题

原文:https://www.studytonight.com/data-structures/activity-selection-problem

活动选择问题是一个优化问题,它处理需要由一个人或一台机器在给定时间范围内执行的非冲突活动的选择。

每个活动都标有开始和结束时间。贪心技术被用于寻找解决方案,因为这是一个优化问题。

什么是活动选择问题?

让我们考虑您有n活动及其开始和结束时间,目标是找到在单个时间范围内可以执行的具有最大数量的非冲突活动的解决方案集,假设只有一个人或一台机器可以执行。

这里有些点要注意:

  • 可能无法完成所有活动,因为它们的时间可能会崩溃。
  • 两个活动,如 ij ,如果si >= fjsj >= fi其中sisj分别表示活动 ij 的开始时间,fifj分别表示活动 ij 的结束时间,则称为不冲突。
  • 贪心方法可以用来寻找解决方案,因为我们想要最大化可以执行的活动的数量。这种方法会贪心地选择每一步完成时间最早的活动,从而产生最优解。

算法的输入数据:

  • act[]包含所有活动的数组。
  • s[]包含所有活动开始时间的数组。
  • f[]包含所有活动结束时间的数组。

从算法输出数据:

  • sol[]指包含最大数量的非冲突活动的解决方案集的数组。

活动选择问题的步骤

下面是我们将遵循的解决活动选择问题的步骤,

第一步:根据给定活动的完成时间,按升序对其进行排序。

第二步:从排序后的数组act[]中选择第一个活动,添加到sol[]数组中。

第 3 步:对act[]中剩余的活动重复第 4 步和第 5 步。

第四步:如果当前选中活动的开始时间大于等于之前选中活动的结束时间,则将其加入sol[]数组。

第五步:选择act[]阵中的下一个活动。

第六步:打印sol[]数组。


活动选择问题示例

让我们用一个例子来追踪上述算法的步骤:

在下表中,我们有 6 个具有相应开始和结束时间的活动,目标是计算具有最大数量非冲突活动的执行计划:

| 开始时间 | 完成时间(f) | 活动名称 |
| five | nine | 第一等的 |
| one | Two | 主动脉第二声 |
| three | four | a3 |
| Zero | six | a4 |
| five | seven | a5 |
| eight | nine | a6 |

一个可能的解决方案是:

第一步:根据给定活动的完成时间,按升序对其进行排序。

我们整理好表格后:

| 开始时间 | 完成时间(f) | 活动名称 |
| one | Two | 主动脉第二声 |
| three | four | a3 |
| Zero | six | a4 |
| five | seven | a5 |
| five | nine | 第一等的 |
| eight | nine | a6 |

第二步:从排序后的数组act[]中选择第一个活动,添加到sol[]数组中,这样 sol = {a2}

第 3 步:对act[]中剩余的活动重复第 4 步和第 5 步。

第四步:如果当前选择的活动开始时间大于等于之前选择的活动结束时间,则添加到sol[]

第五步:选择act[]中的下一个活动

对于上表中给出的数据,

  1. 选择活动 a3 。由于 a3 的开始时间大于 a2 (即s(a3) > f(a2))的结束时间,我们将 a3 添加到解决方案集中。因此 sol = {a2,a3}
  2. 选择 a4 。自s(a4) < f(a3)起,不添加到解集。
  3. 选择 a5 。由于s(a5) > f(a3)a5 被添加到解决方案集中。因此 sol = {a2,a3,a5}
  4. 选择 a1 。由于s(a1) < f(a5)a1 没有被添加到解集中。
  5. 选择 a6a6s(a6) > f(a5)开始添加到解决方案集中。因此 sol = {a2,a3,a5,a6}

第六步:最后打印数组sol[]

因此,最大数量的非冲突活动的执行计划将是:

(1,2) (3,4) (5,7) (8,9)

Activity selection problem example

在上图中,所选活动以灰色突出显示。


活动选择问题算法的实现

现在我们已经对活动选择问题有了一个全面的了解,因为我们已经通过一个例子讨论了算法及其工作细节,下面是相同的 C++ 实现。

:算法可以用任何编程语言轻松编写。

#include <bits/stdc++.h>

using namespace std; 
#define N 6		// defines the number of activities

// Structure represents an activity having start time and finish time. 
struct Activity 
{ 
    int start, finish; 
}; 

// This function is used for sorting activities according to finish time 
bool Sort_activity(Activity s1, Activity s2) 
{ 
    return (s1.finish< s2.finish); 
} 

/* 	Prints maximum number of activities that can
	be done by a single person or single machine at a time. 
*/
void print_Max_Activities(Activity arr[], int n) 
{ 
    // Sort activities according to finish time 
	sort(arr, arr+n, Sort_activity); 

	cout<< "Following activities are selected \n"; 

    // Select the first activity
    int i = 0; 
	cout<< "(" <<arr[i].start<< ", " <<arr[i].finish << ")\n"; 

    // Consider the remaining activities from 1 to n-1 
    for (int j = 1; j < n; j++) 
    { 
    	// Select this activity if it has start time greater than or equal
    	// to the finish time of previously selected activity
      	if (arr[j].start>= arr[i].finish) 
      	{	 
			cout<< "(" <<arr[j].start<< ", "<<arr[j].finish << ") \n"; 
			i = j; 
      	} 
    } 
} 

// Driver program 
int main() 
{ 
    Activity arr[N];
	for(int i=0; i<=N-1; i++)
	{
		cout<<"Enter the start and end time of "<<i+1<<" activity \n";
		cin>>arr[i].start>>arr[i].finish;
    }

	print_Max_Activities(arr, N); 
    return 0; 
}

使用与上述示例相同的输入来执行程序。这将有助于用实际输出来验证结果解集。

Output of activity selection problem program


时间复杂度分析

以下是计算活动选择算法时间复杂度的场景:

  • 案例 1 :当给定的一组活动已经按照完成时间排序,那么就不涉及排序机制,在这种情况下算法的复杂度会是O(n)
  • 案例 2 :当给定的一组活动未排序时,我们将不得不使用 bits/stdc++ 头文件中定义的sort()方法对活动列表进行排序。该方法的时间复杂度将为O(nlogn),这也定义了算法的复杂度。

活动选择问题的现实应用

以下是这个问题的一些实际应用:

  • 在一个房间里安排多个比赛项目,这样每个项目都有自己的开始和结束时间。
  • 在同一台机器上安排多个产品的生产,使每个产品都有自己的生产时间表。
  • 活动选择是运筹学中用于处理实际业务问题的最著名的通用问题之一。


Prim 最小生成树

原文:https://www.studytonight.com/data-structures/prims-minimum-spanning-tree

在本教程中,我们将介绍另一种算法,它使用贪心方法/技术来寻找解决方案。

让我们从一个真实的场景开始来理解这个算法的前提:

  1. A telecommunications organization, has offices spanned across multiple locations around the globe.

    minimum spanning tree example图 1

  2. 它必须使用租用的电话线来连接所有这些办公室。

  3. The cost(in units) of connecting each pair of offices is different and is shown as follows:

    minimum spanning tree example图 2

  4. 因此,该组织希望以最低成本连接其所有办公室。这就要求所有的办公室都应该使用最少数量的租用线路进行连接,以降低有效成本。

  5. 这个问题的解决方案可以通过使用最小生成树的概念来实现,这将在后续章节中讨论。

  6. 本教程还详细介绍了与 Prim 算法相关的概念,该算法用于为给定的图寻找最小生成树。


什么是生成树?

第二图所示的网络基本上代表了一个图 G = (V,E) 有一组顶点 V = {a,b,c,d,E,f} 和一组边 E = { (a,b)、(b,c)、(c,d)、(d,E)、(E,f)、(f,a)、(b,f)、(c,f) } 。该图为:

  • 连通的(每对顶点之间都有一条路径)
  • 无方向(边没有任何相关方向,因此(a,b)和(b,a)是等价的)
  • 加权(每条边都分配了权重或成本)

给定图 G 的生成树G' = (V, E')将包括:

  • G 的所有顶点(V)
  • 所有顶点应通过最小数量的边(E’)连接,这样E' ⊂ E
  • G '可以有最大n-1条边,其中n等于 G 中的边总数
  • ' g '不应有任何周期。这是树和图的基本区别之一一个图可以有循环,但是树不能。因此,树也被定义为非循环图

以下是上图的生成树示例。请注意,生成树中只包含突出显示的边,

spanning tree representation of graph图 3

此外,对于任何给定的图,可能存在多个生成树。例如:除了上图中的生成树,该图还可以有另一个生成树,如下所示:

spanning tree representation of graph图 4

按照惯例,给定图的生成树总数可以定义为:

<sup>n</sup>C<sub>m</sub> = n!/(m!*(n-m)!),其中,

  • n等于给定图中边的总数
  • m等于生成树中边的总数,这样m <= (n-1)

因此,给定图(从上到下的第二个图)的生成树总数可以计算如下:

  • n = 8 ,对于图 2 中给定的图形
  • m = 5 ,因为它对应的生成树只能有 5 条边。增加第 6 条边会导致形成不允许的循环。
  • 所以,S =nCm=8C5= 8!/ (5!* 3!)= 56 ,这意味着可以为给定的图创建不同变化的展树。

什么是最小生成树?

生成树的成本是树中所有边的总权重。例如,图 3 中生成树的成本是 (2+4+6+3+2) = 17 个单位,而图 4 中是 (2+3+6+3+2) = 16 个单位。

因为一个图可以有多个生成树,每个生成树都有自己的成本值,所以目标是找到成本最小的生成树。这被称为最小生成树(MST)

:一个图可以有多个最小生成树,如果图中任意两条边的权重相同。然而,如果每条边都有不同的权重,那么对于任何给定的图,将只有一个最小生成树。


最小生成树的问题陈述

给定一个加权的、无向的连通图 G ,目标是找到 G 的最小生成树 G'

除了最小生成树的 Prim 算法,我们还有寻找最小生成树的 Kruskal 算法。

然而,本教程将只讨论 Prim 算法的基础。

由于该算法旨在寻找代价最小的生成树,因此使用贪心方法来寻找解。

作为查找或创建给定图的最小生成树框架的一部分,我们将遵循以下步骤:

  • 最初,树是空的。
  • 树从一个随机的源顶点开始构建。
  • 每一步都会有一个新的顶点被添加到树中。
  • 这一直持续到图的所有顶点都被添加到树中。

输入数据将为:

A 成本邻接矩阵为出图 G ,称cost

输出将为:

总成本最小的生成树


Prim 的最小生成树算法

下面我们有完整的逻辑,逐步的,这是遵循 prim 的算法:

第 1 步:记录所有已经访问并添加到生成树的顶点。

第二步:最初生成树为空。

第三步:随机选择一个顶点,添加到生成树中。这就变成了根节点

第四步:添加一个新的顶点,比如说 x ,这样

  • x 不在已经构建的生成树中。
  • x 使用最小权边连接到构建的生成树。(因此, x 可以与生成树中已经添加的任何节点相邻)。
  • x 添加到生成树中不应形成循环。

第五步:重复第四步,直到图的所有顶点都加入到生成树中。

第 6 步:打印生成树的总开销。


Prim 最小生成树算法示例

让我们尝试跟踪上面的算法,为图 2 中的图找到最小生成树:

第一步:

  1. 定义key[]数组存储每个顶点的键值(或代价)。将所有顶点初始化为(无穷大)
  2. 定义另一个数组booleanvisited[]来跟踪已经添加到生成树的所有顶点。最初这将是所有顶点的 0 ,因为生成树是空的。
  3. 定义一个数组parent[]来跟踪父顶点。初始化所有顶点的 -1
  4. 初始化最小成本,最小成本= 0

prim minimum spanning tree algo explanation 图 5:树为空时的初始数组

第二步:

选择任意一个任意顶点,说出 f ,设置key[f]=0

set Key 图 6:设置根节点键值

由于其键值最小且未被访问,因此将 f 添加到生成树中。

图 7:根节点

另外,更新以下内容:

  • minCost = 0 + key[f] = 0

  • This is how the visited[] array will look like:

    visited array 图 8:添加根节点后的访问数组

  • Key values for all the adjacent vertices of f will look like this(key value is nothing but the cost or the weight of the edge, for (f,d) it is still infinity because they are not directly connected):

    Key array 图 9:添加根节点后的键数组

:因为 f 是根节点,所以parent[]不会有变化。

parent array 图 10:添加根节点后的父数组

第三步:

将搜索数组key[]visited[]来寻找下一个顶点。

  • f 具有最小键值,但不会被考虑,因为它已经被添加(visited[f]==1)
  • 具有最小关键值的下一个顶点是 c 。从visited[c]==0开始,将添加到生成树中。

adding vertex 图 11:添加顶点 c

再次更新以下内容:

  • minCost = 0 + key[c] = 0 + 1 = 1

  • This is how the visited[] array will look like:

    visited array 图 12:添加顶点 c 后访问数组

  • And, the parent[] array (f becomes the parent of c):

    parent array 图 13:添加根节点后的父数组

  • For every adjacent vertex of c, say v, values in key[v] will be updated using the formula:

    key[v] = min(key[v], cost[c][v])

    这样key[]阵就会变成:

    key array 图 14:添加根节点后的键数组

第四步:

对其余顶点重复步骤 C。

  • Next vertex to be selected is a. And minimum cost will become minCost=1+2=3

    adding vertex 图 15:添加顶点 a

     key visited parent 图 16:添加顶点 a 后更新数组

  • Next, either b or d can be selected. Let's consider b. Then the minimum cost will become minCost=3+3=6

    adding vertex 图 17:给最小生成树添加顶点 b

     key visited parent 图 18:添加顶点 b 后更新数组

  • Next vertex to be selected is d, making the minimum cost minCost=6+3=9

    adding vertex 图 19:添加顶点 d

     key visited parent 图 20:添加顶点 d 后更新数组

  • Then, e is selected and the minimum cost will become, minCost=9+2=11

    adding vertex 图 21:添加顶点 e 这是最终的最小生成树

     key visited parent 图 22:添加顶点 e 后更新的数组(最终数组)

  • 由于现在已经访问了所有顶点,算法终止。

  • 因此,图 21 表示总成本=11 的最小生成树。


Prim 最小生成树算法的实现

现在是时候用 C++ 编写一个程序,用 prim 的算法找出最小生成树了。

#include<iostream>

using namespace std;

// Number of vertices in the graph  
const int V=6;

// Function to find the vertex with minimum key value 
int min_Key(int key[], bool visited[])  
{ 
    int min = 999, min_index;  // 999 represents an Infinite value

    for (int v = 0; v < V; v++) { 
        if (visited[v] == false && key[v] < min) { 
        	// vertex should not be visited
            min = key[v];
			min_index = v;  
        }
    }    
    return min_index;  
}  

// Function to print the final MST stored in parent[]  
int print_MST(int parent[], int cost[V][V])  
{  
    int minCost=0;
	cout<<"Edge \tWeight\n";  
    for (int i = 1; i< V; i++) {
		cout<<parent[i]<<" - "<<i<<" \t"<<cost[i][parent[i]]<<" \n";  
		minCost+=cost[i][parent[i]];
    }
	cout<<"Total cost is"<<minCost;
}  

// Function to find the MST using adjacency cost matrix representation  
void find_MST(int cost[V][V])  
{  
    int parent[V], key[V];
    bool visited[V];

    // Initialize all the arrays 
    for (int i = 0; i< V; i++) { 
        key[i] = 999;    // 99 represents an Infinite value
        visited[i] = false;
        parent[i]=-1;
    }    

    key[0] = 0;  // Include first vertex in MST by setting its key vaue to 0\.  
    parent[0] = -1; // First node is always root of MST  

    // The MST will have maximum V-1 vertices  
    for (int x = 0; x < V - 1; x++) 
    {  
        // Finding the minimum key vertex from the 
        //set of vertices not yet included in MST  
        int u = min_Key(key, visited);  

        visited[u] = true;  // Add the minimum key vertex to the MST  

        // Update key and parent arrays
        for (int v = 0; v < V; v++)  
        {
            // cost[u][v] is non zero only for adjacent vertices of u  
            // visited[v] is false for vertices not yet included in MST  
            // key[] gets updated only if cost[u][v] is smaller than key[v]  
            if (cost[u][v]!=0 && visited[v] == false && cost[u][v] < key[v])
            {  
                parent[v] = u;
                key[v] = cost[u][v];  
            }        
        }
    }

    // print the final MST  
	print_MST(parent, cost);  
}  

// main function
int main()  
{  
    int cost[V][V];
	cout<<"Enter the vertices for a graph with 6 vetices";
    for (int i=0;i<V;i++)
    {
        for(int j=0;j<V;j++)
        {
			cin>>cost[i][j];
        }
    }
	find_MST(cost);  

    return 0;  
} 

输入图形与图 2 中的图形相同。

output 图 23:程序输出


Prim 最小二乘时间复杂度分析

上述 C++ 程序的时间复杂度为 O(V2) ,因为它对输入图使用了邻接矩阵表示。然而,使用邻接表表示,借助二进制堆,可以将 Prim 算法的复杂度降低到 O(ElogV)


最小生成树的现实应用

找到一个 MST 是一个基本问题,它有以下实际应用:

  1. 设计网络,包括计算机网络、电信网络、交通网络、电网和供水网络。

  2. 用于近似求解旅行商问题、最小割问题等问题的算法。

    • 一个旅行推销员问题的目标是在一个只访问每个顶点一次并返回到源顶点的图中找到最短路径。

    • A minimum cut problem is used to find the minimum number of cuts between all the pairs of vertices in a planar graph. A graph can be classified as planar if it can be drawn in a plane with no edges crossing each other. For example,

      planer graph 图 24:平面图

  3. Also, a cut is a subset of edges which, if removed from a planar graph, increases the number of components in the graph

    planer graph 图 25:平面图中的割集

  4. 聚类分析。

  5. 数学表达式的手写识别。

  6. 图像配准和分割



霍夫曼编码算法

原文:https://www.studytonight.com/data-structures/huffman-coding

计算机科学中的每一个信息都被编码为1 和 0的字符串。信息论的目标是通常用最少的比特数来传输信息,使得每个编码都是明确的。本教程讨论了固定长度和可变长度编码以及霍夫曼编码,霍夫曼编码是所有数据编码方案的基础

在计算机中,编码可以定义为有效地传输或存储字符序列的过程。固定长度和可变长度是两种编码方案,解释如下-

固定长度编码 -使用相同的位数为每个字符分配一个二进制代码。因此,像“aabacdad”这样的字符串可能需要 64 位(8 字节)来存储或传输,假设每个字符使用 8 位。

可变长度编码 -与固定长度编码相反,该方案根据字符在给定文本中的出现频率,使用可变位数对字符进行编码。因此,对于像“aabacdad”这样的给定字符串,字符“a”、“b”、“c”和“d”的频率分别是 4、1、1 和 2。由于“a”比“b”、“c”和“d”出现得更频繁,因此它使用的位数最少,其次是“d”、“b”和“c”。假设我们给每个字符随机分配二进制代码如下-

a 0
b 011
c 111
d 11

因此,字符串“aabacdad”被编码为0001101111011(0 | 0 | 011 | 0 | 111 | 11 | 0 | 11),与固定长度编码方案相比使用更少的位数。

但真正的问题在于解码阶段。如果我们尝试解码字符串 0001101111011,它将非常模糊,因为它可以解码为多个字符串,其中很少是-

aaadacdad (0 | 0 | 0 | 11 | 0 | 111 | 11 | 0 | 11)
aaadbcad (0 | 0 | 0 | 11 | 011 | 111 | 0 | 11)
aabbcb (0 | 0 | 011 | 011 | 111 | 011)

…等等

为了防止解码过程中出现这种歧义,编码阶段应该满足“前缀规则”,该规则规定任何二进制代码都不应该是另一个代码的前缀。这将产生独特的可解码代码。上述“a”、“b”、“c”和“d”的代码不遵循前缀规则,因为 a 的二进制代码即 0 是 b 的二进制代码即 011 的前缀,导致不明确的可解码代码。

让我们重新考虑将二进制代码分配给字符“a”、“b”、“c”和“d”。

a 0
b 11
c 101
d 100

使用上述代码,字符串“aabacdad”被编码为 0011011000100(0 | 0 | 11 | 0 | 101 | 100 | 0 | 100)。现在,我们可以将其解码回字符串“aabacdad”

问题陈述-

输入:待传输或存储的符号集及其频率/概率/权重

输出:期望码字长度最小的无前缀变长二进制码。等效地,从根开始具有最小加权路径长度的树状数据结构可以用于生成二进制代码

霍夫曼编码-

霍夫曼编码可用于寻找给定问题陈述的解决方案。

  • 这项技术由大卫·霍夫曼于 1951 年开发,是所有数据压缩和编码方案的基础
  • 这是一种用于无损数据编码的著名算法
  • 它遵循贪心方法,因为它处理生成最小长度的无前缀二进制代码
  • 它使用可变长度编码方案,根据字符在给定文本中出现的频率,为字符分配二进制代码。出现频率最高的字符被分配最小的代码,出现频率最低的字符获得最大的代码

霍夫曼编码的主要步骤是-

第一步 -使用输入符号集和每个符号的权重/频率构建霍夫曼树

  • 类似于二叉树数据结构,需要创建具有 n 叶节点和 n-1 内部节点的霍夫曼树
  • 优先级队列用于构建霍夫曼树,使得具有最低频率的节点具有最高优先级。最小堆数据结构可用于实现优先级队列的功能。
  • 最初,所有节点都是叶节点,包含字符本身以及该字符的权重/频率
  • 另一方面,内部节点包含权重和两个子节点的链接

第二步 -通过遍历霍夫曼树为每个符号分配二进制代码

  • 通常,位“0”代表左边的子级,位“1”代表右边的子级

Algorithm for creating the Huffman Tree-

步骤 1 -为每个字符创建一个叶节点,并使用所有节点构建一个最小堆(频率值用于比较最小堆中的两个节点)

步骤 2-当堆有多个节点时,重复步骤 3 至 5

**步骤 3 -从堆中提取两个频率最小的节点,比如 x 和 y

第 4 步 -创建一个新的内部节点 z,x 作为其左子节点,y 作为其右子节点。同样frequency(z)= frequency(x)+frequency(y)

步骤 5 -将 z 添加到最小堆中

第 6 步 -堆中的最后一个节点是霍夫曼树的根

让我们尝试使用上述算法为以下字符及其频率创建霍夫曼树

| 特性 | 频率 |
| a | Ten |
| e | Fifteen |
| 我 | Twelve |
| o | three |
| u | four |
| s | Thirteen |
| t | one |

步骤 A -为所有角色创建叶节点,并将它们添加到最小堆中。

  • Step 1- Create a leaf node for each character and build a min heap using all the nodes (The frequency value is used to compare two nodes in min heap)

    leaf nodes图 1:每个字符的叶节点

步骤 B -重复以下步骤,直到堆有多个节点

  • 步骤 3 -从堆中提取两个频率最小的节点,比如 x 和 y
  • 第 4 步 -创建一个新的内部节点 z,x 作为其左子节点,y 作为其右子节点。同样频率(z)=频率(x)+频率(y)
  • 步骤 5 -将 z 添加到最小堆中

*** 提取并组合一个以 4 为频率的内部节点

  • 将新的内部节点添加到优先级队列-

Combining nodes 图 2:结合节点 o 和 t

  • 提取并组合一个以 8 为频率的内部节点
  • 将新的内部节点添加到优先级队列-

Combining nodes 图 3:将节点 u 与频率为 4 的内部节点组合

  • 提取并合并节点 I 和 s
  • 将新的内部节点添加到优先级队列-

Combining nodes 图 4:将节点 u 与频率为 4 的内部节点组合

  • 提取并合并节点 I 和 s
  • 将新的内部节点添加到优先级队列-

Combining nodes 图 5:合并节点 I 和 s

  • 提取并合并以 18 为频率的内部节点
  • 将新的内部节点添加到优先级队列-

Combining nodes 图 6:将节点 e 与具有 18 作为频率的内部节点组合

  • 最后,提取并合并以 25 和 33 为频率的内部节点
  • 将新的内部节点添加到优先级队列-

Combining nodes 图 7:通过组合具有 25 和 33 作为频率的内部节点获得的最终霍夫曼树

现在,由于队列中只有一个节点,控件将退出循环

步骤 C -由于频率为 58 的内部节点是队列中唯一的节点,因此它成为霍夫曼树的根。

第 6 步 -堆中的最后一个节点是霍夫曼树的根

遍历霍夫曼树的步骤

  1. 创建辅助数组
  2. 从根节点开始遍历树
  3. 遍历左子时向数组中添加 0,遍历右子时向数组中添加 1
  4. 只要找到叶节点,就打印数组元素

按照上面生成的霍夫曼树的步骤,我们得到了无前缀和可变长度的二进制码,其期望码字长度最小

Binary code to huffman图 8:给霍夫曼树分配二进制代码

| 特性 | 二进制码 |
| 我 | 00 |
| s | 01 |
| e | Ten |
| u | One thousand one hundred |
| t | Eleven thousand and ten |
| o | Eleven thousand and eleven |
| a | One hundred and eleven |

Using the above binary codes-

假设字符串“staeiout”需要通过网络从计算机 A(发送方)传输到计算机 B(接收方)。使用霍夫曼编码的概念,字符串在发送方被编码为“01110101111000110110011010”(01 | 11010 | 111 | 10 | 00 | 11011 | 1100 | 11010)

一旦在接收器端接收到,它将通过遍历霍夫曼树被解码回来。为了解码每个字符,我们从根节点开始遍历树。从字符串的第一位开始。比特流中的“1”或“0”将决定在树中向左还是向右。打印字符,如果我们到达一个叶节点。

Thus for the above bit stream

decoding bit stream图 9:解码比特流

On similar lines-

  • 111 被解码为 a
  • 10 被解码为“e”
  • 00 被解码为“I”
  • 11011 被解码为“o”
  • 1100 被解码为 u
  • 最后,11010 被解码为“t”,从而返回字符串“staeiout”

Implementation-

下面是霍夫曼编码的 C++ 实现。该算法可以根据需要映射到任何编程语言。

	 #include <iostream>
#include <vector>
#include <queue>
#include <string>

using namespace std;

class Huffman_Codes
{
 struct New_Node
 {
  char data;
  size_t freq;
  New_Node* left;
  New_Node* right;
  New_Node(char data, size_t freq) : data(data),
                                 freq(freq),
left(NULL),
right(NULL)
                                 {}
 ~New_Node()
 {
   delete left;
   delete right;
 }
 };

 struct compare
 {
  bool operator()(New_Node* l, New_Node* r)
  {
    return (l->freq > r->freq);
  }
};

New_Node* top;

void print_Code(New_Node* root, string str)
{
if(root == NULL)
   return;

 if(root->data == '$')
 {
  print_Code(root->left, str + "0");
  print_Code(root->right, str + "1");
 }

 if(root->data != '$')
 {
   cout << root->data <<" : " << str << "\n";
   print_Code(root->left, str + "0");
   print_Code(root->right, str + "1");
 }
}

public:
  Huffman_Codes() {};
  ~Huffman_Codes()
  {
    delete top;
  }
  void Generate_Huffman_tree(vector<char>& data, vector<size_t>& freq, size_t size)
  {
   New_Node* left;
   New_Node* right;
   priority_queue<New_Node*, vector<New_Node*>, compare > minHeap;

for(size_t i = 0; i < size; ++i)
   {
      minHeap.push(new New_Node(data[i], freq[i]));
   }

while(minHeap.size() != 1)
    {
      left = minHeap.top();
minHeap.pop();

      right = minHeap.top();
minHeap.pop();

      top = new New_Node('$', left->freq + right->freq);
      top->left  = left;
      top->right = right;
      minHeap.push(top);
     }
    print_Code(minHeap.top(), "");
 }
};

 int main()
 {
  int n, f;
  char ch;
  Huffman_Codes set1;
  vector<char> data;
  vector<size_t> freq;
  cout<<"Enter the number of elements \n";
  cin>>n;
  cout<<"Enter the characters \n";
  for (int i=0;i<n;i++)
  {
      cin>>ch;
data.insert(data.end(), ch);
  }
  cout<<"Enter the frequencies \n";
  for (int i=0;i<n;i++)
  {
      cin>>f;
freq.insert(freq.end(), f);
  }

  size_t size = data.size();
  set1.Generate_Huffman_tree(data, freq, size);

  return 0;
} 

使用与上述示例相同的输入来执行程序。这将有助于用实际输出来验证结果解集。

output图 10:输出

时间复杂度分析-

由于霍夫曼编码使用最小堆数据结构来实现优先级队列,因此复杂度为 0(nlogn)。这可以解释如下-

  • 构建一个最小堆需要O(nlogn)时间(将一个元素从根节点移动到叶节点需要O(logn)比较,在最坏的情况下,这是针对 n/2 个元素完成的)。
  • 构建一个最小堆需要O(nlogn)时间(将一个元素从根节点移动到叶节点需要O(logn)比较,在最坏的情况下,这是针对 n/2 个元素完成的)。

由于构建最小堆和排序是按顺序执行的,因此整个过程的算法复杂度计算为 0(nlogn)

我们也可以有一个线性时间算法,如果字符已经按照它们的频率排序的话。

霍夫曼编码的优点-

  • 这种编码方案节省了大量存储空间,因为生成的二进制码长度可变
  • 它生成较短的二进制代码,用于编码在输入字符串中更频繁出现的符号/字符
  • 生成的二进制代码没有前缀

霍夫曼编码的缺点-

  • 与有损编码技术相比,像霍夫曼编码这样的无损数据编码方案实现了更低的压缩比。因此,像霍夫曼编码这样的无损技术只适用于编码文本和程序文件,而不适用于编码数字图像。
  • 霍夫曼编码是一个相对较慢的过程,因为它使用两个过程-一个用于建立统计模型,另一个用于编码。因此,使用霍夫曼编码的无损技术比其他技术要慢得多。
  • 由于所有二进制码的长度不同,解码软件很难检测编码数据是否损坏。这可能导致不正确的解码,进而导致错误的输出。

霍夫曼编码的实际应用

  • 霍夫曼编码广泛用于类似GZIP, PKZIP (winzip) and BZIP2的压缩格式。
  • JPEG, PNG and MP3这样的多媒体编解码器使用霍夫曼编码(更准确地说是前缀码)
  • 霍夫曼编码仍然主导着压缩行业,因为由于专利问题,避免了较新的算术和范围编码方案。


迪克斯特拉算法

原文:https://www.studytonight.com/data-structures/dijkstras-algorithm

迪杰斯特拉的算法发表于 1959 年,以其发现者埃德格·迪杰斯特拉的名字命名,他是一名荷兰计算机科学家。该算法旨在寻找具有非负边权重的有向或无向图中的最短路径。

在我们研究这个算法的细节之前,让我们先简单了解一下以下内容:

  • :图是定义为 G=(V,E)的非线性数据结构,其中 V 是顶点的有限集合,E 是边的有限集合,使得每条边都是连接任意两个顶点的直线或圆弧。
  • 加权图:这是一种特殊类型的图,其中每条边都被赋予一个数值,称为权重
  • 连通图:这类图中每对顶点之间都存在一条路径
  • 图 G 的生成树是一个子图 G ’,它包括 G 的所有顶点,这些顶点与最小数量的边相连。因此,对于具有 n 个顶点的图 G,生成树 G’将具有 n 个顶点和最大 n-1 条边。

问题陈述

给定一个加权图 G,目标是找到从给定源顶点到 G 的所有其他顶点的最短路径。该图具有以下特征-

  • 顶点集V
  • 加权边组E,使得(q,r)表示顶点 q 和 r 之间的,成本(q,r)表示其权重

迪克斯特拉算法:

  • 这是一种单源最短路径算法,旨在找到给定问题陈述的解决方案
  • 该算法适用于有向图和无向图
  • 它只适用于连通图
  • 该图不应包含负边权重
  • 该算法主要遵循贪心方法寻找局部最优解。但是,它也使用动态规划方法来构建全局最优解,因为先前的解被存储并进一步添加,以获得到源顶点的最终距离
  • 该算法的主要逻辑基于以下公式-
    dist[r]=min(dist[r], dist[q]+cost[q][r])

该公式规定,当且仅当dist[q]+cost[q][r] is less than dist[r]的值为时,与顶点 q 相邻的距离顶点 r 将被更新。这里

  • dist 是一个一维数组,它在每一步跟踪从源顶点到所有其他顶点的最短距离,并且
  • 成本是一个二维数组,表示图的成本邻接矩阵
  • 这个公式同时使用了贪心和动态方法。贪心方法用于寻找最小距离值,而动态方法用于组合先前的解( dist[q] 已经被计算并用于计算 dist[r] )

算法-

Input Data-

  • 图 G 的成本邻接矩阵,比如成本
  • 源顶点,比如 s

Output Data-

  • 从 s 到 G 中所有其他顶点的最短路径的生成树

以下是寻找解决方案的步骤-

第一步;Set dist[s]=0,S=ϕ // s 是源顶点,s 是包含所有访问顶点的一维数组

第二步:对于除 s 之外的所有节点 v,设置 dist[v]= ∞

第三步:找到 q 不在 S,这样 dist[q]最小//顶点 q 不应该被访问

步骤 4 :将 q 添加到 S //将顶点 q 添加到 S,因为它现在已经被访问过了

第 5 步:更新与 q 相邻的所有 r 的距离【r】,使得 r 不在 S 中//不应访问顶点 r dist[r]=min(dist[r], dist[q]+cost[q][r]) //贪心和动态方法

第 6 步:重复第 3 步到第 5 步,直到所有节点都在 S //中,重复,直到所有顶点都被访问过

第 7 步:打印从源顶点 u 到所有其他顶点的最短路径的数组距离

第 8 步:退出

让我们试着用下面的例子来理解这个算法的工作原理

weight graph图 1:输入图(加权和连通)

给定上述加权连通图和源顶点 s,以下步骤用于寻找表示 s 和所有其他顶点之间最短路径的树-

步骤 A -使用以下算法步骤初始化距离数组–

  • 步骤 1 -设置 dist[s]=0,S=ϕ // u 是源顶点,s 是具有所有访问顶点的一维数组

  • 步骤 2 -对于除 s 之外的所有节点 v,设置 dist[v]=∠

| 访问顶点集 | S | A | B | C | D |
| | Zero | ∞ | ∞ | ∞ | ∞ |

graph 图 2:初始化 dist[]后的图形

步骤 B - a)选择源顶点 s,因为距离[s]最小,s 不在 s 中

第 3 步 -发现 q 不在 S 中,这样 dist[q]最小//不应访问顶点

通过将其添加到 S 来访问 S

步骤 4 -将 q 添加到 S //将顶点 q 添加到 S,因为它现在已经被访问过了

步骤 c) 对于所有尚未被访问(不在 S 中)的 S 的相邻顶点,即 A 和 C,使用以下算法步骤更新距离数组-

第 5 步 -更新与 q 相邻的所有 r 的距离【r】,使得 r 不在 S 中//不应访问顶点 r dist[r]=min(dist[r], dist[q]+cost[q][r]) //贪心和动态方法

dist[A]= min(dist[A], dist[s]+cost(s, A)) = min(∞, 0+9) = 9
dist[C] = min(dist[C], dist[s]+cost(s, C)) = min(∞, 0+5) = 5

因此 dist[]更新如下-

| 访问顶点集 | S | A | B | C | D |
| [s] | Zero | nine | ∞ | five | ∞ |

步骤 C -重复步骤 B

  1. 选择并访问顶点 C,因为它没有被访问过(不在 S 中),距离[C]是最小的
  2. 更新 C 的相邻顶点(即 A、B 和 D)的距离数组

第 6 步 -重复第 3 步到第 5 步,直到所有节点都在 S

dist[A]=min(dist[A], dist[C]+cost(C,A)) = min(9, 5+2)= 7

dist[B]= min(dist[B], dist[C]+cost(C,B)) = min(∞, 5+9)= 14

dist[D]= min(dist[D], dist[C]+cost(C,D))= min((∞,5+4)=9

这将更新 dist[]如下-

| 访问顶点集 | S | A | B | C | D |
| [s] | Zero | nine | ∞ | five | ∞ |
| [南、北] | Zero | seven | Fourteen | five | nine |

继续类似的路线,重复步骤 B,直到所有的顶点都被访问(添加到 S)。dist[]也会在每次迭代中更新,结果如下–

| 访问顶点集 | S | A | B | C | D |
| [s] | Zero | nine | ∞ | five | ∞ |
| [南、北] | Zero | seven | Fourteen | five | nine |
| [南、中、北] | Zero | seven | eight | five | nine |
| [南、中、南、北] | Zero | seven | eight | five | nine |
| [南、中、北、南] | Zero | seven | eight | five | nine |

dist[]的最后一次更新给出了从 s 到所有其他顶点的最短路径值

给定图的合成最短路径生成树如下-

shortest path图 3:最短路径生成树

Note-

  • 取决于源顶点,同一图可以有多个最短路径生成树

Implementation-

下面是迪克斯特拉算法的 C++ 实现

注:
算法可以根据需要映射到任意编程语言。

	 #include<iostream>
using namespace std;
#define V 5  //Defines total number of vertices in the graph
#define INFINITY 999
int min_Dist(int dist[], bool visited[])   
//This method used to find the vertex with minimum distance and is not yet visited
{
	int min=INFINITY,index;                 //Initialize min with infinity
	for(int v=1;v<=V;v++)
	{
		if(visited[v]==false &&dist[v]<=min)      
		{
			min=dist[v];
			index=v;
		}
	}
	return index;
}
void Dijkstra(int cost[V][V],int src) //Method to implement shortest path algorithm
{
	int dist[V];                             
	bool visited[V];
	for(int i=1;i<=V;i++)                    //Initialize dist[] and visited[] 
	{
		dist[i]=INFINITY;
		visited[i]=false;	
	}
	//Initialize distance of the source vertec to zero
	dist[src]=0;                                   
	for(int c=2;c<=V;c++)                           
	{
		//u is the vertex that is not yet included in visited and is having minimum 
		int u=min_Dist(dist,visited);            distance
		visited[u]=true;                          //vertex u is now visited 
		for(int v=1;v<=V;v++)                    
//Update dist[v] for vertex v which is not yet included in visited[] and
//there is a path from src to v through u that has smaller distance than
// current value of dist[v]
		{
			if(!visited[v] && cost[u][v] &&dist[u]+cost[u][v]<dist[v])
			dist[v]=dist[u]+cost[u][v];
		}
	}
	 //will print the vertex with their distance from the source
	cout<<"The shortest path  "<<src<<" to all the other vertices is: \n";
	for(int i=1;i<=V;i++)                      
	{
	   if(i!=src)
	   cout<<"source:"<<src<<"\t destination:"<<i<<"\t MinCost is:"<<dist[i]<<"\n";
	}
}
int main()
{
	int cost[V][V], i,j, s;
	cout<<"\n Enter the cost matrix weights";
	for(i=1;i<=V;i++)      //Indexing ranges from 1 to n
          for(j=1;j<=V;j++)
          {
cin>>cost[i][j];
			//Absence of edge between vertices i and j is represented by INFINITY
             if(cost[i][j]==0)     
               cost[i][j]=INFINITY;    
           }
cout<<"\n Enter the Source Vertex"; 
cin>>s;

	Dijkstra(cost,s);
	return 0;	
} 

该程序使用与图 1 中相同的输入图来执行。这将有助于用实际输出来验证结果解集。

Output of program图 4:输出

时间复杂度分析-

以下是计算迪克斯特拉算法时间复杂度的例子

  • 案例 1 -当图 G 使用邻接矩阵表示时-这个场景在上面的 C++ 基础程序中实现。由于实现包含两个嵌套的 for 循环,每个循环的复杂度为 O(n) ,因此迪克斯特拉算法的复杂度为 O(n2) 。请注意,这里的 n 指的是给定图中的顶点总数
  • 情况 2 -当使用邻接表表示图 G 时-时间复杂度,在这种情况下降低到 O(|E| + |V| log |V|) 其中|E|表示图中的边数,|V|表示图中的顶点数

迪克斯特拉算法的缺点-

迪克斯特拉算法不能获得正确的具有负边的加权图的最短路径。让我们考虑下面的例子来解释这个场景-

disadvantages of algorithm图 5:负边加权图

选择源顶点为 A,算法工作如下-

步骤 A -初始化距离数组(dist)-

| 访问顶点集 | A | B | C | D |
| | Zero | ∞ | ∞ | ∞ |

步骤 B -选择顶点 A,因为dist[A]是最小值,A 不在 S 中。访问 A 并将其添加到 S 中。对于 A 的所有尚未访问(不在 S 中)的相邻顶点,即 C、B 和 D,更新距离数组

dist[C]= min(dist[C], dist[A]+cost(A, C)) = min(∞, 0+0) = 0

dist[B] = min(dist[B], dist[A]+cost(A, B)) = min(∞, 0+1) = 1

dist[D]= min(dist[D], dist[A]+cost(A, D)) = min(∞, 0+99) = 99

因此 dist[]更新如下-

| 访问顶点集 | A | B | C | D |
| [答] | Zero | one | Zero | Ninety-nine |

步骤 C -重复步骤 B

  1. 选择并访问顶点 C,因为它没有被访问过(不在 S 中),距离[C]是最小的
  2. 距离数组不会更新,因为 C 没有相邻的顶点

| 访问顶点集 | A | B | C | D |
| [答] | Zero | one | Zero | Ninety-nine |
| [甲、丙] | Zero | one | Zero | Ninety-nine |

继续类似的路线,重复步骤 B,直到所有的顶点都被访问(添加到 S)。dist[]也会在每次迭代中更新,结果如下–

| 访问顶点集 | A | B | C | D |
| [答] | Zero | one | Zero | Ninety-nine |
| [甲、丙] | Zero | one | Zero | Ninety-nine |
| [甲、丙、乙] | Zero | one | Zero | Ninety-nine |
| [甲、丙、乙、丁] | Zero | one | Zero | Ninety-nine |

因此,以下是从 A 到 B、C 和 D 的最短距离-

A->C = 0 A->B = 1 A->D = 99

但是这些值是不正确的,因为我们可以有另一条路径从 AC,A- > D- > B- > C总成本= -200 小于 0。发生这种情况是因为一旦访问了一个顶点并将其添加到集合 S 中,它就再也不会“回头”了。因此,迪克斯特拉的算法并不试图找到一条更短的路径到达已经被添加到 s 的顶点。

  • 它执行盲搜索来寻找最短路径,因此,消耗大量时间并浪费其他资源

迪克斯特拉算法的应用

  • 交通信息系统使用迪克斯特拉算法从给定的源位置跟踪目的地
  • 开源路径优先(OSPF) 是一种基于互联网的路由协议,使用 Dijkstra 算法来寻找从源路由器到网络中其他路由器的最佳路由
  • 它被电话和蜂窝网络用于路由管理
  • 它也被地理信息系统(GIS) 使用,例如谷歌映射,用于寻找从 A 点到 B 点的最短路径


高级数据结构

高级树

多维树数据结构

原文:https://www.studytonight.com/advanced-data-structures/nary-tree

N 元树是一种允许我们拥有特定节点的n个子节点的树,因此得名 N 元,这使得它比非常常见的二叉树稍微复杂一些,后者允许我们最多拥有一个特定节点的 2 个子节点。

N 元树的图示如下所示:

N-ary Tree

在上面显示的 N 元树中,我们可以注意到总共有 11 个节点有些节点有三个子节点,有些只有一个。在二叉树的情况下,更容易存储这些子节点,因为我们可以将两个节点(即左节点和右节点)分配给一个特定的节点来标记它的子节点,但这里并没有那么简单。为了存储任何树节点的子节点,我们使用了另一种数据结构,主要是 C++ 中的 vector 和 Java 中的 LinkedList。

多维树的实现

当我们处理非线性数据结构时,首先要做的是为它们创建我们自己的结构(Java 中的构造器)。就像在二叉树的情况下,我们使用一个类TreeNode,在这个类中,我们创建我们的构造器并拥有我们的类级变量。

考虑下面的代码片段:

public static class TreeNode{
        int val;
        List<TreeNode> children = new LinkedList<>();

        TreeNode(int data){
            val = data;
        }

        TreeNode(int data,List<TreeNode> child){
            val = data;
            children = child;
        }
}

在上面的代码片段中,我们有一个名为TreeNode的类,该类又包含两个同名的构造器,但它们本质上是重载的(方法名相同但参数不同)。我们还有两个标识符,其中一个是存储任何特定节点的值的 val,然后我们有一个 List 来存储树的任何节点的子节点。

上面的片段包含了我们的树的基本结构,现在只剩下制作一个,然后稍后我们将看到如何使用级别顺序遍历来打印树。为了构建一棵树,我们将使用我们在上面的类中定义的构造器。

考虑下面的代码片段:

public static void main(String[] args) {
        // creating an exact replica of the above pictorial N-ary Tree
        TreeNode root = new TreeNode(1);
        root.children.add(new TreeNode(2));
        root.children.add(new TreeNode(3));
        root.children.add(new TreeNode(4));
        root.children.get(0).children.add(new TreeNode(5));
        root.children.get(0).children.add(new TreeNode(6));
        root.children.get(0).children.add(new TreeNode(7));
        root.children.get(1).children.add(new TreeNode(8));
        root.children.get(2).children.add(new TreeNode(9));
        root.children.get(2).children.add(new TreeNode(10));
        root.children.get(2).children.add(new TreeNode(11));
        printNAryTree(root);
}

首先,我们创建了我们的 N 元树的根节点,然后我们必须给这个根节点分配一些子节点,我们通过使用点(.)操作符和访问根节点的子属性来实现这一点,然后使用List接口提供的添加方法向根节点添加不同的子节点。一旦我们添加了根节点的所有子节点,就到了添加每个新级别节点的子节点的时候了,我们首先使用列表接口提供的 get 方法访问该节点,然后将相应的子节点添加到该节点。

最后,我们打印这个 N 元树,我们通过调用printNAryTree方法来完成。

现在,由于打印一棵树并不像遍历一组项目那么简单,我们有不同的技术(精确地说是算法)可以使用。这些主要是:

  • 有序遍历

  • 前序遍历

  • 后序遍历

  • 层级顺序遍历

出于本教程的目的,我们将使用级别顺序遍历方法,因为它更容易理解,前提是您之前已经看过它在二叉树上的工作方式。

层级顺序遍历(打印 N 元树)

任何树的级别顺序遍历都考虑到这样一个事实,即我们希望首先在根级别打印节点,然后前进到下一个级别,并不断重复这个过程,直到我们到达最后一个级别。我们利用队列数据结构来存储特定级别的节点。

考虑一个简单的 N 元树,如下所示:

N-ary Tree

上述树的级别顺序遍历如下所示:

1
2 3 4 5

考虑下面的代码片段:

private static void printNAryTree(TreeNode root){
        if(root == null) return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            int len = queue.size();
            for(int i=0;i<len;i++) { // so that we can reach each level
                TreeNode node = queue.poll();
                System.out.print(node.val + " ");
                for (TreeNode item : node.children) { // for-Each loop to iterate over all childrens
                    queue.offer(item);
                }
            }
            System.out.println();
        }
}

整个代码如下所示:

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class NAryTree {
    public static class TreeNode{
        int val;
        List<TreeNode> children = new LinkedList<>();

        TreeNode(int data){
            val = data;
        }

        TreeNode(int data,List<TreeNode> child){
            val = data;
            children = child;
        }
    }

    private static void printNAryTree(TreeNode root){
        if(root == null) return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            int len = queue.size();
            for(int i=0;i<len;i++) {
                TreeNode node = queue.poll();
                assert node != null;
                System.out.print(node.val + " ");
                for (TreeNode item : node.children) {
                    queue.offer(item);
                }
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        root.children.add(new TreeNode(2));
        root.children.add(new TreeNode(3));
        root.children.add(new TreeNode(4));
        root.children.get(0).children.add(new TreeNode(5));
        root.children.get(0).children.add(new TreeNode(6));
        root.children.get(0).children.add(new TreeNode(7));
        root.children.get(1).children.add(new TreeNode(8));
        root.children.get(2).children.add(new TreeNode(9));
        root.children.get(2).children.add(new TreeNode(10));
        root.children.get(2).children.add(new TreeNode(11));
        printNAryTree(root);
    }
} 

上面代码的输出是:

1
2 3 4
5 6 7 8 9 10 11

我们可以将这个输出与开始时 N 元树的图形表示进行比较,每个级别节点都包含相同的值。

二叉树的类型

以下是二叉树的类型:

1. 全 N 和树

全 N 元树是一种 N 元树,它允许每个节点有 0 或 N 个子节点。

考虑如下所示的完整 N 元树的图示:

full N-ary Tree

请注意,上述 N 元的所有节点都有 4 个子节点或 0 个子节点,因此满足该属性。

2.完全 N 元树

一个完整的 N 元树是一个 N 元树,在这个树中,除了最后一级节点之外,树的每一级节点都应该是完整的(应该正好有 N 个子节点),如果最后一级节点不完整,那么这些节点必须是“尽可能左边的”。

考虑如下所示的完整 N 元树的图形表示:

complete N ary tree

3.完美 N 元树

一个完美的 N 元树是一个完整的 N 元树,但是叶节点的级别必须相同。

考虑如下所示的完美 N 元树的图形表示:

perfect n-ary tree

结论

  • 我们了解了什么是二叉树。
  • 我们还学习了如何在 Java 中实现 N 元树(通过级别顺序遍历)。
  • 然后我们了解了总共有哪些不同类型的 N 元树。


树型数据结构

原文:https://www.studytonight.com/advanced-data-structures/avl-tree

AVL 树是另一种特殊的树,它有几个特性使它特别。这些是:

  • 这是一个本质上平衡的 BST。

  • 它是自我平衡的。

  • 它不是完全平衡的。

  • 每个子树也是一个 AVL 树。

AVL 树的图示如下所示:

AVL Tree

当被解释时,我们可以说这是一个高度平衡的二叉查找树。高度平衡表示每个节点的左右子树高度之差不能大于 1(即高度(左)-高度(右)< = 1 )。

AVL Tree with Balance Factor

请注意,上面的 BST 中的每个节点都包含两个值,左值表示该节点的左子树的高度,右值表示该节点的右子树的高度,可以看出,在没有一个节点上,我们的值差大于 1,因此使其成为平衡的 AVL Tree。

一个自平衡树意味着当我们试图在这个 BST 中插入任何元素,如果它违反了任何节点的平衡因子,那么它会相应地动态旋转自己,使自己自平衡。众所周知,AVL 树是第一个被提出的著名的动态平衡树。

它不是完美平衡的,完美平衡意味着每个节点的右子树和左子树之间的高度等于 0

完美平衡自动车辆定位树的图示如下所示:

Perfectly Balanced AVL Tree

上述 AVL 树的所有节点的平衡因子等于 0( 高度(左)-高度(右)= 0 ),使其成为完美的 AVL 树。还需要注意的是,一个完美的 BST 和一个完美的 AVL 树是一样的。如果我们仔细看看上面所有的图形表示,我们可以清楚地看到,AVL 树的每个子树也是一个 AVL 树。

现在我们再来看两个图片,其中一个是 AVL 树,一个不是。

Difference

虽然上面的两棵树都是 BST,但是上面的图中只有左边的 BST 是 AVL 树,因为它高度平衡。在右 BST 中,我们有两个违规节点(即 8 和 10),在这两种情况下,平衡因子都大于 2。需要注意的是,这个树可以通过一定的方式进行旋转,使其成为 AVL 树。

为什么是 AVL 树?

当我们已经有了类似的数据结构(即 BST 的)时,为什么我们还需要它的复杂版本呢?。答案在于,BST 在某些场景中有一些限制,使得搜索、插入等操作成本很高(与O(n)一样高)。

考虑下面两个 BST 的图示:

BST difference

左 BST 的高度为O(logn),右 BST 的高度为O(n),因此左 BST 的搜索操作时间复杂度为O(logn),右偏斜的为O(n),这也是其最坏的情况。因此,如果我们有这样一个倾斜的树,那么使用 BST 就没有任何好处,因为当涉及到时间和空间复杂度时,它就像一个链表。

这就是为什么我们需要一个平衡的 BST,这样所有的基本操作都保证了 O(logN)的时间复杂度。

树旋转

如果 AVL 树遇到任何违反平衡因子的情况,那么它会尝试做一些旋转来使树再次平衡。总共有四次旋转,我们将逐一查看。主要有:

  • 向左旋转

  • 右旋转

  • 左右旋转

  • 左右旋转

1.向左旋转

当违规发生在违规节点的左子节点的左子树中时,将执行此循环。考虑下面一个不平衡的 BST 的图形表示,为了做到这一点,我们将做一些旋转。

Right Skewed AVL

很明显,这不是一个 AVL 树,但是考虑到违规发生的节点,我们把这个节点作为一个枢纽来进行我们的旋转。右边的树很重,导致问题的节点是 17,如果我们移除那个节点,我们将有一个平衡的 BST(即 AVL)。由于它严重向右倾斜,我们将向左旋转以使其平衡。

考虑将上面的右斜树做成 AVL 树的图示。

Left Rotation Explained

2.右旋转

当违规发生在违规节点的右子节点的右子树中时,将执行此循环。考虑下面一个不平衡的 BST 的图形表示,为了做到这一点,我们将做一些旋转。

Left Skewed BST

很明显,这不是一个 AVL 树,但是考虑到违规发生的节点,我们把这个节点作为一个枢纽来进行我们的旋转。树的左边很重,导致问题的节点是 3,如果我们移除那个节点,我们将有一个平衡的 BST(即 AVL)。由于它严重偏左,我们将做一个右旋转,使其平衡。

考虑将上面左倾的树做成 AVL 树的图示。

Explained Difference Right Rotate

3.左右旋转

当违规发生在违规节点的左子节点的右子树中时,将执行此循环。考虑下面一个不平衡的 BST 的图形表示,为了做到这一点,我们将做一些旋转。

Left-Right Rotation

很明显,这不是一个 AVL 树,但是考虑到违规发生的节点,我们把这个节点作为一个枢纽来进行我们的旋转。导致问题的节点是 18,就好像我们去掉那个节点,我们就会有一个平衡的 BST(即 AVL)。因为这个问题是因为左子树的右子树,我们将进行左右旋转,使其平衡。

考虑将上面的树做成 AVL 树的图示。

Explained AVL Difference

4.左右旋转

当违规发生在违规节点的右子节点的左子树中时,将执行此循环。考虑下面一个不平衡的 BST 的图形表示,为了做到这一点,我们将做一些旋转。

Right-Left BST

很明显,这不是一个 AVL 树,但是考虑到违规发生的节点,我们把这个节点作为一个枢纽来进行我们的旋转。导致问题的节点是 7,如果我们移除那个节点,我们将有一个平衡的 BST(即 AVL)。由于问题是由于右子树的左子树,我们将进行左右旋转,使其平衡。

考虑将上面的树做成 AVL 树的图示。

Explained AVL Tree

树插入

让我们取一组数组元素,并构建这些元素的 AVL 树。让,nums = [12 , 3 , 9 , 4 , 6 , 2]

制作 AVL 树(带旋转)的完整步骤如下所示。

Final Image

要点:

  • 具有 N 个节点的 AVL 树的最小楼层高度(logN)可以是 2。

  • 节点数为 N 的 AVL 树的高度不能超过 1.44(logN)基数 2。

  • 高度为 h 的 AVL 树中的最大节点数可以是:2^H+1 - 1

  • AVL 树的高度为 h 的最小节点数可以表示为:N(h) = N(h-1) + N(h-2) + 1,n>2,其中 N(0) = 1,N(1) = 2。

结论

  • 我们了解了什么是 AVL 树以及为什么需要它。
  • 然后,我们学习了 AVL 树中可能的不同类型的旋转,以使其成为一个平衡的旋转。
  • 在旋转之后,我们还在 AVL 树中做了一个插入示例。
  • 最后,我们谈到了我们应该记住的与 AVL 不同的关键点。


堆数据结构

原文:https://www.studytonight.com/advanced-data-structures/heap

堆是遵循两个属性的特殊类型的树。这些属性是:

  • 对于某些h > 0(完全二叉树属性),所有叶子必须处于hh-1级别。

  • 节点的值必须是>=(或<=)其子节点的值,称为堆属性。

考虑如下所示的图示:

Heap

在上面显示的图片中,最左边的树表示一个堆(最大堆),它右边的两个树不是堆,因为中间的树违反了第一个堆属性(不是完整的二叉树),左边的最后一个树违反了第二个堆属性(17 < 19)。

堆的类型

如果我们考虑堆的属性,那么我们可以有两种类型的堆。这些主要是:

  • 最小堆

  • 最大堆

最小堆

在此堆中,节点的值必须小于或等于其子节点的值。

考虑下面最小堆的图示:

Min Heap

可以清楚地看到,上述堆中任何节点的值总是小于其子节点的值。

最大堆

在此堆中,节点的值必须大于或等于其子节点的值。

考虑下面最大堆的图示:

Max Heap

可以清楚地看到,上述堆中任何节点的值总是大于其子节点的值。

建立一个堆

让我们看看一些操作,比如在堆中插入一个元素或者从堆中删除一个元素。

1.插入元素:

  • 首先将堆大小增加 1。

  • 然后在可用位置插入新元素(最左边的位置?最后一级)。

  • 从底部到顶部堆积元素(向上冒泡)。

构建堆包括向堆中添加元素。让我们考虑一个元质数组,即 nums = [10,5,17,4,22]。我们想用这些元素做一个最大堆,我们这样做的方式如下图所示。

Buidling Heap

每当我们在构建堆时添加一个元素,它很可能会违反其中一个属性。我们通过简单地用最大节点填充每个级别来处理第一个堆属性,然后当我们进入下一个级别时,我们先填充左边的子级,然后填充右边的子级。但是我们仍然有可能违反第二个堆属性,在这种情况下,我们只是冒泡我们已经插入的当前元素,并试图找到它在堆中的正确位置。冒泡包括将当前元素与其父元素交换,直到堆成为最大堆。在最小堆的情况下,我们在向堆中添加元素的同时执行相同的过程。

上面的表示总共显示了三个违规(17,22,22),在所有这些情况下,我们基本上已经用父节点交换了当前节点,因此冒泡了。还可以注意到,这种冒泡的过程也被称为筛上。

现在让我们来看另一个例子,我们泡下去。考虑下面显示的树(不是堆)的图形表示:

Bubble Down

2.删除元素:

  • 将堆的第一个元素(根)复制到某个变量中

  • 将堆的最后一个元素放在根的位置

  • 向下冒泡,使其成为有效的堆

每当我们删除一个元素时,我们只需删除根元素,并用堆的最后一个元素(最后一级的最右边的子元素)替换它。我们这样做是因为我们只想维护第一个属性,就好像我们从堆中取出任何其他元素,我们将没有有效的完整二叉树。然后我们将这个节点放在根节点上,这个节点可能不满足堆的第二个属性,因此我们向下冒泡,使它成为一个有效的堆。还可以注意到,这种向下冒泡的过程也被称为向下筛选。

考虑如下所示的图示:

Delete Heap

二进制堆的应用

  • 二进制堆用于一种著名的排序算法,称为堆排序。

  • 二进制堆也是实现优先级队列的主要原因,因为因为它们,像 add(),remove()等几个优先级队列操作的时间复杂度为 O(n)。

  • 它们也是解决 Kth 最小/ Kth 最大元素问题的最优选选择。

堆:时间复杂度分析

让我们看看堆的各种操作的时间复杂度。

1.插入元素:

在堆中插入一个元素包括在叶级别插入它,然后如果它违反了堆的任何属性,就冒泡它。我们知道堆是一个完整的二叉树,完整二叉树的高度是(log N),其中 N 代表树中元素的个数。因此,如果我们考虑最糟糕的情况,我们可能不得不将这个新插入的节点交换到最上面,那么在树的每一层我们将有 1 个交换,因此我们将需要 N 个交换。因此,在二进制堆中插入元素的最坏时间复杂度是:0(对数 N)

2.删除元素:

从堆中删除元素包括移除根节点,然后将其与最后一级的最后一个节点交换,然后如果这个新的根节点违反了任何堆属性,我们需要将其与子节点交换,直到树是有效的二进制堆。因为,在最坏的情况下,我们可能不得不将这个新的根节点与较低级别的节点交换到最底层(叶级别),这又意味着树的高度,因此从二进制堆中删除节点的时间复杂度依次为:O(log N)

3.获取最小/最大元素:

在二进制堆中获取 max(或 min)元素只是一个恒定的时间操作,因为我们知道,如果是 min 堆,最小值将是根节点,同样,在 max 堆的情况下,最大值元素也将是根节点。所以,提取最小值/最大值的时间复杂度为:O(1)

结论

  • 我们了解了什么是堆,然后解释了什么是最小/最大堆。
  • 然后我们学习了如何插入堆,然后从堆中删除一个元素。
  • 然后我们讨论了二进制堆的应用。
  • 最后,我们讨论了堆的时间复杂度。


实现堆

原文:https://www.studytonight.com/advanced-data-structures/implementing-heaps

在上一篇文章中,我们了解了堆的所有知识。现在是实施它们的时候了。数组是实现堆的首选,因为堆有完整的二叉树属性,我们可以确信不会浪费数组位置。

让我们考虑如下所示的二进制堆,这个堆可以用一个数组来表示,如下图所示。

Array Heap

实现堆

让我们看看如何实现一个堆数据结构。

1.堆的结构

我们需要一个数组来存储堆的元素,此外,我们还需要一个变量来表示堆的大小。考虑下面的代码片段:

private int[] items = new int[10];
private int size;

初始容量也可以是动态的,但这里我选择了 10 的固定长度来表示相同的容量。

2.插入到堆中

当我们想要将一个项目插入到堆中时,我们将简单地将它插入到数组中,然后如果它不满足任何堆属性,就执行bubbleUp()操作。代码如下所示:

private void insert(int item){
        if(isFull()){
            throw new IllegalStateException();
        }
        items[size++] = item;
        bubbleUp();
}

一个案例可能会到达堆已满的地方,然后如果我们试图向其中插入更多的项目,它应该会返回一个异常。isFull()方法是这样的:

private boolean isFull(){ return size == items.length; }

在这个isFull()调用返回 false 之后,我们向前移动,将项目插入到我们的堆中,并增加数组的大小。现在,最重要的部分是纠正我们在堆中插入的这个元素的位置。我们用bubbleUp()方法来做。bubbleUp()方法代码如下:

private void bubbleUp(){
        int index = size - 1;
        while(index > 0 && items[index] > items[parent(index)]){
            swap(index,parent(index));
            index = parent(index);
        }
}

在上面的方法中,我们获取刚刚插入的元素的索引,然后在这个元素比父元素大的情况下用父元素交换它,同时我们更新索引,这样我们就不会选择错误的元素。swap()方法是这样的:

private void swap(int left,int right){
        int temp = items[left];
        items[left] = items[right];
        items[right] = temp;
}

还需要注意的是,我们在bubbleUp()方法中调用的是一个父方法,该父方法返回给我们一个当前索引的父。该方法的代码如下所示:

private int parent(int index){ return (index - 1)/2; }

以上方法是我们将元素插入二进制堆所需的全部方法。

3.从堆中移除

与插入堆相比,从堆中移除元素是一个有点棘手的过程,因为在这个例子中,我们需要bubbleDown(),这个向下冒泡的过程包括检查父元素的有效性,以及尽可能向左插入树以保持完整的二叉树属性的方法。

remove()方法是这样的:

private void remove(){
        if(isEmpty()){
            throw new IllegalStateException();
        }
        items[0] = items[--size];
        bubbleDown();
}

第一个检查是确保我们没有试图从空堆中移除任何东西。然后我们在开始处插入元素,然后bubbleDown()将元素放到它的正确位置。bubbleDown()方法是这样的:

private void bubbleDown(){
        int index = 0;
        while(index <= size && !isValidParent(index)){
            int largerChildIndex = largerChildIndex(index);
            swap(index,largerChildIndex);
            index = largerChildIndex;
        }
}

我们正在检查我们拥有的索引应该小于大小,并确保父节点不应该是有效的(应该小于子值和其他检查)。largerChildIndex()方法返回给我们子项目,我们将在向下冒泡时用它替换当前项目。largerChildIndex()的代码是这样的:

private int largerChildIndex(int index){
        if(!hasLeftChild(index)) return index;
        if(!hasRightChild(index)) return leftChildIndex(index);
        return (leftChild(index) > rightChild(index)) ? leftChildIndex(index) : rightChildIndex(index);
}

isValidParent()方法代码如下:

private boolean isValidParent(int index){
        if(!hasLeftChild(index)) return true;
        var isValid = items[index] >= leftChild(index);
        if(hasRightChild(index)){
            isValid &= items[index] >= rightChild(index);
        }
        return isValid;
}

在上面的代码片段中,我们只是确保父级是有效的,并且如果左边的子级是 null,那么我们返回 true。leftChild()rightChild()hasLeftChild()hasRightChild()的方法是这样的:

private int leftChild(int index){
        return items[leftChildIndex(index)];
}

private int rightChild(int index){
        return items[rightChildIndex(index)];
}

private boolean hasLeftChild(int index){
        return leftChildIndex(index) <= size;
}

private boolean hasRightChild(int index){
        return rightChildIndex(index) <= size;
}

上面的方法调用方法来获取二进制堆元素的左右子元素,它们是:

private int leftChildIndex(int index){
        return 2*index + 1;
}

private int rightChildIndex(int index){
        return 2*index + 2;
}

现在,我们已经完成了从堆中插入或删除元素所需的所有方法。完整的代码如下:

public class Heap {

    private int[] items = new int[10];
    private int size;

    private void insert(int item){
        if(isFull()){
            throw new IllegalStateException();
        }
        items[size++] = item;
        bubbleUp();
    }

    private void remove(){
        if(isEmpty()){
            throw new IllegalStateException();
        }
        items[0] = items[--size];
        bubbleDown();
    }

    private int largerChildIndex(int index){
        if(!hasLeftChild(index)) return index;
        if(!hasRightChild(index)) return leftChildIndex(index);
        return (leftChild(index) > rightChild(index)) ? leftChildIndex(index) : rightChildIndex(index);
    }

    private boolean isValidParent(int index){
        if(!hasLeftChild(index)) return true;
        var isValid = items[index] >= leftChild(index);
        if(hasRightChild(index)){
            isValid &= items[index] >= rightChild(index);
        }
        return isValid;
    }

    private int leftChild(int index){
        return items[leftChildIndex(index)];
    }

    private int rightChild(int index){
        return items[rightChildIndex(index)];
    }

    private int leftChildIndex(int index){
        return 2*index + 1;
    }

    private int rightChildIndex(int index){
        return 2*index + 2;
    }

    private boolean hasLeftChild(int index){
        return leftChildIndex(index) <= size;
    }

    private boolean hasRightChild(int index){
        return rightChildIndex(index) <= size;
    }

    private boolean isFull(){
        return size == items.length;
    }

    private boolean isEmpty(){
        return size == 0;
    }

    private void bubbleUp(){
        int index = size - 1;
        while(index > 0 && items[index] > items[parent(index)]){
            swap(index,parent(index));
            index = parent(index);
        }
    }

    private void bubbleDown(){
        int index = 0;
        while(index <= size && !isValidParent(index)){
            int largerChildIndex = largerChildIndex(index);
            swap(index,largerChildIndex);
            index = largerChildIndex;
        }
    }

    private int parent(int index){
        return (index - 1)/2;
    }

    private void swap(int left,int right){
        int temp = items[left];
        items[left] = items[right];
        items[right] = temp;
    }

    private int getMax(){
        return items[0];
    }

    public static void main(String[] args) {
        Heap heap = new Heap();
        heap.insert(10);
        heap.insert(5);
        heap.insert(17);
        heap.insert(4);
        heap.insert(22);
       /// heap.remove();
        System.out.println("Done!");
    }
} 

结论

  • 我们学习了如何实现堆,主要是 bubbleUp()bubbleDown() 方法。


TRIE 数据结构示例

原文:https://www.studytonight.com/advanced-data-structures/trie-data-structure-explained-with-examples

A Trie 是一种高级数据结构,有时也被称为前缀树或数字树。它是以有序和高效的方式存储数据的树。我们通常使用“T4”来存储字符串。trie 的每个节点可以有多达 26 个引用(指针)。

trie 的每个节点由两件事组成:

  • 一个角色

  • 布尔值用于实现该字符是否代表单词的结尾。

一般来说,try 用于存储英文字符,因此每个字符可以有 26 个引用。trie 中的节点不存储整个键,而是存储键的一部分(通常是字符串的一个字符)。当我们从根节点向下遍历到叶节点时,我们可以从密钥的这些小部分构建密钥。

让我们通过插入一些单词来建立一个 trie。下面是同样的图示,我们有 5 个单词,然后我们把这些单词一个接一个地插入我们的 trie。

TRIE data structure

如上图所示,当我们从根节点向下遍历到叶节点时,可以形成关键字(单词)。可以注意到,绿色突出显示的节点代表单词的endOfWord布尔值,这又意味着该特定单词在该节点完成。此外,trie 的根节点是空的,因此它可以引用 trie 用来存储的字母表的所有成员,并且 trie 的任何节点的子节点最多可以有 26 个引用。尝试在本质上是不平衡的,不像 AVL 树。

为什么要使用 Trie 数据结构?

当我们谈论从数据结构中检索值的最快方法时,散列表通常会出现在我们的脑海中。虽然本质上非常高效,但与散列表相比,仍然很少被提及, trie 比散列表高效得多,而且它们还具有几个优势。主要是:

  • 不会有任何冲突,从而使最差的性能优于没有正确实现的哈希表。

  • 不需要散列函数。

  • trie 中字符串的查找时间为O(k),其中 k =单词的长度。

  • 当单词不在一个 trie 中时,它可能需要更少的时间。

实施尝试:

我们将用 Java 语言实现 Trie 数据结构。

三节点声明:

class TrieNode {
    boolean isEndOfWord;
    TrieNode children[];

    public TrieNode(){
        isEndOfWord = false;
        children = new TrieNode[26];
    }
}

请注意,我们在上面的 TrieNode 类中有两个字段,如前所述,布尔 isEndOfWord 关键字和一个名为 children 的 Trie 节点数组。现在让我们初始化 trie 类的根节点。

TrieNode root;

public Trie() {
    root = new TrieNode();
}

trie 数据结构中有两个关键功能,它们是:

  • 搜索

  • 插入

在三中插入:

当我们在 trie 中插入一个字符(键的一部分)时,我们从根节点开始,然后搜索一个引用,该引用对应于我们试图在 trie 中插入其字符的字符串的第一个键字符。两种情况是可能的:

  • 如果存在一个引用,那么我们沿着树向下遍历引用到下一个子级。

  • 引用不存在,然后我们创建一个新节点,并使用与当前关键字符匹配的父引用来引用它。我们重复这个步骤,直到我们到达密钥的最后一个字符,然后我们将当前节点标记为结束节点,算法完成。

考虑下面的代码片段:

public void insert(String word) {
    TrieNode node = root;

    for (char c : word.toCharArray()) {
        if (node.children[c-'a'] == null) {
            node.children[c-'a'] = new TrieNode();
        }
        node = node.children[c-'a'];
    }
    node.isEndOfWord = true;
}

在 trie 中搜索:

trie 中的一个键被存储为从根节点开始的路径,它可能一直到叶节点或某个中间节点。如果我们想在 trie 中搜索一个关键字,我们从根节点开始,然后向下遍历。如果我们找到了要搜索的关键字的下一个字符的引用匹配,那么有两种情况:

  1. 存在下一个字符的引用,因此我们沿着这个链接向下移动,并继续搜索下一个关键字符。

  2. 下一个字符不存在引用。如果钥匙没有其他字符存在,并且该字符被标记为isEndOfWord = true,那么我们返回 true ,这意味着我们找到了钥匙。否则,还有两种情况是可能的,在每种情况下,我们都返回 false 。这些是:

    1. 键中还有一些关键字符,但是由于路径终止,我们无法向下遍历,因此键不存在。

    2. 键中没有剩余字符,但最后一个字符没有标记为isEndOfWord = false。因此,搜索关键字只是我们试图在 trie 中搜索的关键字的前缀。

考虑下面的代码片段:

public boolean search(String word) {
    return isMatch(word, root, 0, true);
}

public boolean startsWith(String prefix) {
    return isMatch(prefix, root, 0, false);
}

public boolean isMatch( String s, TrieNode node, int index, boolean isFullMatch) {
    if (node == null)
        return false;

    if (index == s.length())
        return !isFullMatch || node.isEndOfWord;

    return isMatch(s, node.children[s.charAt(index) - 'a'], index + 1, isFullMatch);      
}

方法startsWith()用于查找 trie 中是否存在所需的密钥前缀。还有,无论是search()还是startsWith() 的方法都利用了isMatch() 的方法。

整个代码:

class Trie {
    class TrieNode {
        boolean isEndOfWord;
        TrieNode children[];

        public TrieNode(){
            isEndOfWord = false;
            children = new TrieNode[26];
        }
    }

    TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    public void insert(String word) {
        TrieNode node = root;

        for (char c : word.toCharArray()) {
            if (node.children[c-'a'] == null) {
                node.children[c-'a'] = new TrieNode();
            }
            node = node.children[c-'a'];
        }
        node.isEndOfWord = true;
    }

    public boolean search(String word) {
        return isMatch(word, root, 0, true);
    }

    public boolean startsWith(String prefix) {
        return isMatch(prefix, root, 0, false);
    }

    public boolean isMatch( String s, TrieNode node, int index, boolean isFullMatch) {
        if (node == null)
            return false;

        if (index == s.length())
            return !isFullMatch || node.isEndOfWord;

        return isMatch(s, node.children[s.charAt(index) - 'a'], index + 1, isFullMatch);      
    }    

    public static void main(String[] args){
        Trie trie = new Trie();
        trie.insert("cat");
        trie.insert("car");
        trie.insert("dog");
        trie.insert("pick");
        trie.insert("pickle");
        boolean isPresent = trie.search("cat");
        System.out.println(isPresent);
        isPresent = trie.search("picky");
        System.out.println(isPresent);
        isPresent = trie.startsWith("ca");
        System.out.println(isPresent);
        isPresent = trie.startsWith("pen");
        System.out.println(isPresent);

    }
}

上面的输出如下所示:

错误的

真实的

错误的

排序应用程序

  • 现实世界中最常见的尝试是我们在搜索引擎上获得的自动完成功能(现在其他地方也是)。在搜索栏中键入内容后,我们可能输入的潜在单词的树会大大减少,这反过来又允许程序为我们键入的单词列举可能的字符串类型。

  • Trie 在我们想要存储一个词的附加信息的情况下也有帮助,比如这个词的流行度,这使得它如此强大。你可能已经看到了,当你在搜索栏上输入【脚】时,你会在说【步道】之前得到【足球】。因为“足球”是一个非常流行的词。

  • Trie 还帮助检查一个单词的正确拼写,因为一个稍微拼错的单词的路径是相似的。

  • 字符串匹配是另一种尝试大量超越的情况。

要点

  • 创建 trie 的时间复杂度是O(m*n) ,其中 m = trie 中的字数,n =每个单词的平均长度。

  • 在 trie 中插入节点的时间复杂度为O(n) ,其中 n =我们试图插入的单词的长度。

  • 在 trie 中插入节点的空间复杂度为O(n) ,其中 n =我们试图插入的单词的长度。

  • 在 trie 中搜索关键字(单词)的时间复杂度是O(n) ,其中 n =我们正在搜索的单词的长度。

  • 在 trie 中搜索关键字(词)的空间复杂度是O(1)

  • 搜索一个关键字(词)的前缀也有O(n) 的时间复杂度和O(1)的空间复杂度。

结论

  • 我们了解了什么是特里,为什么我们需要特里。

  • 我们还在 Java 中实现了 trie,其中插入和搜索是实现的主要方法。

  • 然后我们讨论了 trie 数据结构在现实世界中的应用,接下来是我们还应该记住的关于 Trie 的几个关键点。



B 树数据结构

原文:https://www.studytonight.com/advanced-data-structures/b-trees-mway-trees-data-structure

B 树是一种特殊类型的 M 路搜索树。

双向树

在学习 B-Trees 之前,我们需要知道什么是 M-way 树,以及 B-tree 是一种特殊类型的 M-way 树。多路(多路)树是具有以下属性的树:

  • 树中每个节点最多可以有 m 个子节点。

  • 树中的节点最多有 (m-1) 个关键字段和指向子节点的指针(引用)。

考虑下图所示的 M 路树的图示。

M-way Tree data structure

上图为 4 向树,每个节点最多可以有 3(4-1)个关键字段和最多 4 个子节点。也是 4 向搜索树

双向搜索树

M 路搜索树是一种更受约束的 M 路树,这些约束主要应用于关键字段及其值。使其成为多路搜索树的多路树的约束条件是:

  • 树中的每个节点可以与 m 子节点和 m-1 关键字段相关联。

  • 树的任何节点中的键都是按排序顺序排列的(升序)。

  • 第一个 K 子节点中的键是小于这个节点的****Kth键。

  • 最后一个 (m-K )孩子的按键高于第 K 个按键。

考虑下面显示的 M 路搜索树的图示:

3-way search tree

M-way 搜索树与 M-way 树具有相同的优势,这使得搜索和更新操作更加高效。尽管如此,它们可能会变得不平衡,这反过来又让我们面临同样的问题,即在一棵倾斜的树上寻找一把钥匙,这并不是一个很大的优势。

在双向搜索树中搜索:

如果我们想要在 M 路搜索树中搜索一个值,比如说 X ,并且当前我们处于包含来自 Y1、Y2、Y3,.....,Yk 。那么总共有 4 种情况可以处理这种情况,它们是:

  • 如果 X < Y1 ,那么我们需要递归遍历 Y1 的左子树。

  • 如果 X > Yk ,那么我们需要递归遍历 Yk 的右子树。

  • 如果 X = Yi ,对于一些 i ,那么我们就完了,可以回归了。

  • 最后也是唯一剩下的情况是,当对于某些 i 我们有 Yi < X < Y(i+1) 时,那么在这种情况下我们需要递归地遍历存在于 YiY(i+1) 之间的子树。

例如,考虑上面显示的 3 向搜索树,比如说,我们想要搜索一个关键字(X)等于 60 的节点。然后,考虑到上述情况,对于根节点,第二个条件适用, (60 > 40) ,因此我们向下移动到 40 的右子树。现在,最后一个条件仅有效,因此我们遍历位于 5570 之间的子树。最后,在向下遍历时,我们有了我们一直在寻找的价值。

二叉树数据结构:

B 树是 M 路搜索树的扩展。除了具有 M 路搜索树的所有属性之外,它还具有自己的一些属性,这些属性主要是:

  • B 树中的所有叶节点都在同一级别。

  • 所有内部节点必须有 M/2 子节点。

  • 如果根节点是非叶节点,则它必须至少有两个子节点。

  • 除根节点外,所有节点必须至少有【M/2】-1键,最多有 M-1 键。

考虑如下所示的 B 树的图示:

B Tree

在 B 树中搜索:

在 B 树中搜索关键字就像在 M 路搜索树中搜索一样,我们刚刚在上面看到过。考虑下图所示的 B 树的图示,假设我们想在下图所示的 B 树中搜索一个键 49。我们按照以下方式进行:

  • 将项目 49 与根节点 75 进行比较。自 49 < 75 遂,移至其左子树。

  • 此后, 40 < 49 < 58 ,遍历右子树 40。

  • 49 > 44 ,向右移动。对比 49

  • 我们找到了 49 个,所以回来了。

考虑如下所示的图示:

B Tree Search

在 B 树中插入:

在 B 树中插入是在叶节点级别完成的。我们按照给定的步骤来确保插入后 B 树是有效的,这些步骤是:

  • 首先,我们遍历 B 树,找到要插入的键适合的节点。

  • 如果该节点包含少于 M-1 个键,那么我们以递增的顺序插入该键。

  • 如果那个节点恰好包含 M-1 键,那么我们有两种情况?按照递增的顺序插入新元素,通过中值将节点拆分为两个节点,将中值元素向上推至其父节点,最后如果父节点还包含 M-1 键,那么我们需要重复这些步骤。

考虑如下所示的图示:

Inserting B Tree

现在,考虑我们要在上面显示的 B 树中插入一个键 9,插入键 9 后的树看起来像这样:

Violation in B Tree

由于发生了违规,我们需要将中间节点推送到父节点,然后将节点分成两部分,因此 B 树的最终外观是:

Updated B Tree

在 B 树中删除:

删除 B 树中的一个键包括两种情况,它们是:

  • 从叶节点删除密钥

  • 从内部节点删除密钥

从叶节点删除密钥:

如果我们想要删除存在于 B 树的叶节点中的键,那么我们有两种可能的情况,它们是:

  • 如果包含我们想要删除的键的节点反过来包含的键数超过了有效 B 树所需的最小键数,那么我们可以简单地删除该键。

考虑如下所示的图示:

Delete operation B Tree

比方说,我们想要删除键 64,并且其中存在 64 的节点的节点数超过了 B 树所需的最小节点数,即 2。所以,我们可以简单地删除这个节点。

删除 64 后的最终树如下所示:

Delete B Tree-1

  • 如果包含我们想要删除的键的节点反过来包含有效 B 树所需的最小键数,那么有三种情况是可能的:

    • 为了从 B 树中删除这个键,我们可以从紧邻的左节点(左兄弟)借用一个键。这个过程是我们将最高值的键从左边的兄弟移动到父节点,然后将最高值的父键移动到我们刚刚删除键的节点。

    • 在另一种情况下,我们可能不得不从紧邻的右节点(右兄弟)借用一个键。这个过程是我们将最低值的键从右边的兄弟节点移动到父节点,然后将最高值的父键移动到我们刚刚删除键的节点。

    • 最后一种情况是,左兄弟或右兄弟都不处于给当前节点任何值的状态,因此在这一步中,我们将与他们中的任何一个进行合并,并且合并还将包括来自父节点的键,然后我们可以从节点中删除该键。

案例 1 绘画作品:

Deletion B Tree 3

在我们删除 23 之后,我们询问左边的兄弟,然后将 16 移动到父节点,然后向下推 20,得到的 B 树是:

Delete B Tree 6

案例 2 绘画作品:

simple-1

在我们删除 72 之后,我们询问右边的兄弟,然后将 77 移动到父节点,然后将 75 向下推,得到的 B 树是:

Delete 8

案例 3 绘画作品:

Delete 11

从叶节点中删除 65 后,我们将得到最终的 B 树,如下所示:

Delete B Tree Final

从内部节点删除密钥:

  • 如果我们想删除一个存在于内部节点中的键,那么我们可以取这个键的顺序前置的值,或者如果取那个顺序前置违反了 B 树属性,我们可以取这个键的顺序后续

  • 在有序前身方法中,我们在存在我们的键的节点的左子节点中提取最高值。

  • 在有序后继方法中,我们提取密钥所在节点的右子节点中的最低值。

上述情况的图示:

  • 内部前身进场
    Internal
    删除后,我们的 B 树:
    Internal 2
  • 内部继任者进场
    Internal 3
    删除 95 后,我们的树会是这样的:

要点:

  • B 树中搜索、插入和删除操作的时间复杂度为 O(log n)。

  • B 树中的最小键数应该是[]T2【M/2]-1。

  • B 树中最大键数应为 M-1。

  • B 树中的所有叶节点应该在同一级别。

  • 二叉树中节点的所有键都是按升序排列的。

  • 在 SQL 中使用 b 树来提高查询效率。

  • B 树中的每个节点最多只能有 M 个子节点。

结论:

在本文中,我们了解了什么是 M 路树,M 路树和 M 路搜索树有什么区别。此外,我们还学习了应用于 M 路树的约束,以使其成为 B 树。然后我们学习了搜索、插入和删除操作。



B+ 树数据结构

原文:https://www.studytonight.com/advanced-data-structures/b-plus-trees-data-structure

A B+ 树是 B 树的扩展,使得搜索、插入和删除操作更加高效。我们知道 B 树允许内部节点和叶节点中的数据指针和键值,这当然成为 B 树的缺点,因为在特定级别插入节点的能力降低,从而增加了节点级别,这当然是没有好处的。B+ 树通过简单地在叶节点级存储数据指针并且只在内部节点存储键值来减少这个缺点。还应该注意的是,叶级的节点是相互链接的,因此使得数据指针的遍历更加容易和高效。

当我们想要在主存中存储大量数据时,B+ 树就派上了用场。因为我们知道主内存的大小没有那么大,所以利用 B+ 树,它的内部存储密钥的节点(访问记录)存储在主内存中,而包含数据指针的叶节点实际上存储在辅助内存中。

B+ 树的图示如下:

B+ trees data structure

为什么是 B+ 树?

  • B+ 树存储记录,这些记录以后可以在相同次数的磁盘访问中获取。

  • B+ 树的高度保持平衡,并且与 B 树相比非常小,即使存储在 B 树中的记录数量相同。

  • 拥有更少的级别数使得访问记录变得非常容易。

  • 由于叶节点像链表一样相互连接,我们可以很容易地按顺序搜索元素。

在 B+ 树中插入

  • 在 B+ 树中执行搜索操作,以检查这个新节点应该到达的理想铲斗位置

  • 如果存储桶未满(不违反 B+ 树属性),则将该节点添加到该存储桶中。

  • 否则,将节点拆分为两个节点,并将中间节点(准确地说是中间节点)推到父节点,然后插入新节点。

  • 如果父节点在那里,并且当前节点不断变满,请重复上述步骤。

考虑下面显示的图示,以理解 B+ 树中的插入操作:

B+ trees data structure

让我们尝试在上面显示的 B+ 树中插入 57,得到的 B+ 树将如下所示:

B+ trees data structure

我们知道,我们插入值为 57 的键的桶(节点)现在违反了 B+ 树的属性,因此我们需要按照上面的步骤分割这个节点。拆分后,我们将中间节点推送到父节点,生成的 B+ 树如下所示:

B+ trees data structure

在 B+ 树中搜索:

在 B+ 树中搜索类似于在 BST 中搜索。如果当前值小于搜索关键字,则遍历左侧子树,如果大于,则首先遍历当前桶(节点),然后检查理想位置在哪里。

考虑下面 B+ 树的表示来理解搜索过程。假设我们想在下面给定的 B+ 树中搜索一个值等于 59 的键。

B+ trees data structure

现在我们知道 59 < 69,因此我们遍历左边的子树。

B+ trees data structure

现在我们已经找到了内部指针,它将指向我们需要的搜索值。

B+ trees data structure

最后,我们以线性方式遍历这个桶,以获得所需的搜索值。

B+ trees data structure

B+ 树中的删除:

删除是一个有点复杂的过程,出现了两种情况:

  • 它只存在于叶级

  • 或者,它还包含一个来自内部节点的指针。

仅删除叶节点:

如果它只是作为叶节点位置出现,那么我们可以简单地删除它,为此我们首先进行搜索操作,然后删除它。

考虑如下所示的图示:

B+ trees data structure

删除 79 后,剩下的是下面的 B+ 树。

B+ trees data structure

如果存在指向叶节点的指针,则删除:

B+ trees data structure

找到要删除的节点后,我们还必须删除指向该节点的内部指针,然后我们最终需要移动下一个节点指针以移动到父节点。

B+ trees data structure

结论:

  • 我们了解了什么是 B+ 树,以及它与 B 树的区别。

  • 然后我们了解了为什么我们需要 B+ 树。

  • 最后,我们学习了对 B+ 树型搜索、插入和删除记录(键)的不同操作。



图介绍

原文:https://www.studytonight.com/advanced-data-structures/introduction-to-graphs

图是一种高级数据结构,用于组织互联网络中的项目。图中的每一项都称为一个节点(或顶点,这些节点通过连接。

在下图中,我们有一个简单的图,其中总共有五个节点和六条边。

Simple Graph with 5 nodes and 6 edges

任何图中的节点都可以称为实体,连接不同节点的边定义了这些实体之间的关系。在上图中,我们有一组节点 {V} = {A,B,C,D,E} 和一组边, {E} = {A-B,A-D,B-C,B-D,C-D,D-E}

真实世界的例子

图表的一个很好的例子是一个由社会上有联系的人组成的网络,他们通过一个简单的联系联系在一起,这个联系就是他们是否认识对方。

考虑下图,其中显示了一个社交网络的图示,总共有五个人。

Graph Example

上面两个人之间的一条线表示他们彼此认识。如果名字之间没有界线,那么他们就根本不认识对方。这里的名字相当于一个图的节点,定义“相知”关系的线简单来说相当于一个图的边。还应该注意的是,相互了解的关系是双向的,就像“Abhishek”了解“Mukul”一样,“Mukul”了解“Abhishek”。

上面描述的社交网络只不过是一张图表。

图的类型

让我们涵盖各种不同类型的图表。

1.空图

如果图中没有边,则称该图为空。

空图的图示如下:

Null graph example

2.无向图

如果我们看一下我们在上面的真实世界例子中的图表示,我们可以清楚地看到不同的节点通过一个链接(即边)连接在一起,而这个边没有任何与之相关的方向。比如“Anuj”和“Deepak”之间的边缘是双向的,因此两者之间的关系是双向的,原来是“Anuj”知道“Deepak”,而“Deepak”也知道“Anuj”。这种类型的图,其中的关系是双向的或没有一个方向,被称为无向图。

另一个无向图的图示如下:

Undirected Graph Representation

3.有向图

如果两个人的关系是这样的呢,“Shreya”认识“Abhishek”,但是“Abhishek”不认识“Shreya”。这种类型的关系是单向的,它确实包括一个方向。带有箭头的边基本上表示关系的方向,这样的图称为有向图。

该图的图示如下:

Directed Graph Representation

还可以注意到,从“Shreya”到“Abhishek”的边是“Shreya”的输出边和“Abhishek”的输入边。

4.循环图

一个包含至少一个来回遍历的节点的图称为循环图。简单地说,一个图应该至少有一个循环形成,才能被称为循环图。

循环图的图示如下:

Cyclic Graph

很容易看出,节点(a,b,c)之间存在一个循环,因此它是一个循环图。

5.无圈图

一个我们无法从一个节点开始,又无法遍历回同一个节点,或者根本没有一个循环的图被称为非循环图。

非循环图的图示如下:

Acyclic Graph

6.加权图

当一个图的边有一些相关的权重时,我们称这个图为加权图。权重通常是一个可以表示任何东西的数字,完全取决于图中节点之间的关系。

加权图的图示如下:

Weighted Graph

还可以注意到,如果任何图没有任何与之相关的权重,我们简单地称之为未加权图。

7.连通图

在图的每两个节点之间有一条路径的图称为连通图。这里的路径意味着我们能够从一个节点“A”遍历到任意一个节点“B”。简而言之,我们可以说,如果我们从图的一个节点开始,我们将总是能够从该节点遍历到图的所有其他节点,从而获得连通性。

下图给出了连通图的图示:

Connected Graph

8.不连通图

不连通的图简称为不连通图。在断开的图中,我们将无法从图的每两个节点之间找到路径。

断开图的图示如下:

Disconnected Graph

9.完全图

如果一个图的每一对顶点(节点)都有一条边,那么这个图就是一个完整的图。

完整图的图示如下:

Complete Graph

10.多重图

如果图中任意一对节点之间有两条或两条以上的边,则称该图为多重图。

多重图的图示如下:

Multigraph

常用图术语

  • 路径 -一系列交替的节点和边,使得每个连续的节点通过边连接。

  • 循环 -起始节点和结束节点相同的路径。

  • 简单路径 -一条我们不会再遇到顶点的路径。

  • -一条边,它的移除只会使图断开。

  • 森林 -森林是没有周期的图。

  • -没有任何循环的连通图。

  • -图中的度是入射到特定节点上的边的数量。

  • 邻居 -如果顶点“A”和“B”之间存在边,我们称它们为邻居。

结论

  • 借助不同人之间的无向图,我们了解了什么是图。
  • 我们了解了总共有多少种类型的图。
  • 我们了解了在谈论图及其子图时使用的常用术语。


图表示——邻接矩阵和列表

原文:https://www.studytonight.com/advanced-data-structures/graph-representations-adjacency-matrix-and-list

我们有两种方法来表示图,它们是:

  • 邻接矩阵

  • 邻接表

这两者各有利弊。在本教程中,我们将介绍这两种图表示以及如何实现它们。

邻接矩阵

邻接矩阵表示使用矩阵(表),其中矩阵的第一行和第一列表示图的节点(顶点)。其余单元格的包含 0 或 1 (如果是加权图,可以包含关联的权重 w )。

每个行 X 列的交点指向一个单元格,该单元格的值将帮助我们确定该行所表示的顶点与该列所表示的顶点是否相连。如果 v1 X v2 的单元格的值等于 1,那么我们可以得出结论,这两个顶点 v1 和 v2 通过一条边相连,否则它们根本不相连。

考虑下面给出的图表:

Adjacency Matrix

上图是一个无向图,其邻接矩阵如下:

Matrix

上面的矩阵是上图的邻接矩阵表示。如果我们仔细观察,我们可以看到矩阵是对称的。现在让我们看看有向图的邻接矩阵是如何变化的。

考虑下面给出的图表:

Directed Graph

对于上面显示的有向图,邻接矩阵看起来像这样:

Directed Adjacency Matrix

邻接矩阵的实现

邻接矩阵的结构(Java 中的构造器)如下所示:

public AdjacencyMatrix(int vertex){
        this.vertex = vertex;
        matrix = new int[vertex][vertex];
}

还应该注意的是,我们有两个类级变量,比如:

int vertex;
int[][] matrix;

上面我们有一个名为 AdjacencyMatrix 的构造器,它计算图中存在的顶点的数量,然后为我们的全局顶点变量赋值,并创建一个相同大小的 2D 矩阵。现在,由于我们的结构部分已经完成,我们只需要将边添加到一起,我们的方法是:

public void addEdge(int start,int destination){
        matrix[start][destination] = 1;
        matrix[destination][start] = 1; // for un-directed graph
}

在上面的addEdge函数中,我们还为从目的地到开始节点的方向指定了 1,就像在这段代码中我们看到的无向图的例子一样,其中的关系是一个双向过程。如果它是一个有向图,那么我们可以简单地使这个值等于 0,我们就会有一个有效的邻接矩阵。

现在只剩下打印图表了。

public void printGraph(){
        System.out.println("Adjacency Matrix : ");
        for (int i = 0; i < vertex; i++) {
            for (int j = 0; j <vertex ; j++) {
                System.out.print(matrix[i][j]+ " ");
            }
            System.out.println();
        }
}

整个代码如下所示:

public class AdjacencyMatrix {
    int vertex;
    int[][] matrix;

    // constructor
    public AdjacencyMatrix(int vertex){
        this.vertex = vertex;
        matrix = new int[vertex][vertex];
    }

    public void addEdge(int start,int destination){
        matrix[start][destination] = 1;
        matrix[destination][start] = 1;
    }

    public void printGraph(){
        System.out.println("Adjacency Matrix : ");
        for (int i = 0; i < vertex; i++) {
            for (int j = 0; j <vertex ; j++) {
                System.out.print(matrix[i][j]+ " ");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        AdjacencyMatrix adj = new AdjacencyMatrix(4);
        adj.addEdge(0,1); // 0 as the array is 0-indexed
        adj.addEdge(1,2);
        adj.addEdge(2,3);
        adj.printGraph();
    }
}

上面的输出如下所示:

邻接矩阵:
0 1 0 0
1 0 1 0
0 1 0 1
0 0 1 0

邻接表

在邻接表表示中,我们有一个链表数组,其中数组的大小是图中顶点(节点)的数量。每个顶点都有自己的链表,其中包含它所连接的节点。

考虑以下图表:

Adjacency Matrix

上图是一个无向图,它的邻接表如下:

Adjacency List

第一列包含我们在上面的图中拥有的所有顶点,然后这些顶点中的每一个都包含一个链表,该链表又包含每个顶点所连接的节点。对于有向图而言,唯一的变化是链表将只包含出现入射边的节点。

考虑以下图表:

Directed Graph

上图是有向图,其邻接表如下所示:

Adjacency List

邻接表的实现

邻接表的结构(Java 中的构造器)如下所示:

public AdjacencyList(int vertex){
        this.vertex = vertex;
        list = new LinkedList[vertex];
        for(int i=0;i<vertex;i++){
            list[i] = new LinkedList<Integer>();
        }
}

上面的构造器将顶点的数量作为一个参数,然后将这个值赋给类级变量,然后我们创建一个图中顶点大小的链表数组。最后,我们为链表数组中的每一项创建一个空链表。

还应该注意的是,我们有两个类级变量,比如:

int vertex;
LinkedList<Integer> []list;

现在我们已经打好了基础,剩下的唯一事情就是把边加在一起,我们是这样做的:

public void addEdge(int start,int destination){
        list[start].addFirst(destination);
        list[destination].addFirst(start); // un-directed graph
}

我们取一条边的起点和终点的顶点,我们只需将目标顶点插入起点顶点的链表中,反之亦然(无向图也是如此)。

现在只剩下打印图表了。

public void printGraph(){
        for (int i = 0; i < vertex ; i++) {
            if(list[i].size()>0) {
                System.out.print("Node " + i + " is connected to: ");
                for (int j = 0; j < list[i].size(); j++) {
                    System.out.print(list[i].get(j) + " ");
                }
                System.out.println();
            }
        }
}

整个代码如下所示:

import java.util.LinkedList;

public class AdjacencyList {
    int vertex;
    LinkedList<Integer> []list;

    public AdjacencyList(int vertex){
        this.vertex = vertex;
        list = new LinkedList[vertex];
        for(int i=0;i<vertex;i++){
            list[i] = new LinkedList<Integer>();
        }
    }

    public void addEdge(int start,int destination){
        list[start].addFirst(destination);
        list[destination].addFirst(start); // un-directed graph
    }

    public void printGraph(){
        for (int i = 0; i < vertex ; i++) {
            if(list[i].size()>0) {
                System.out.print("Node " + i + " is connected to: ");
                for (int j = 0; j < list[i].size(); j++) {
                    System.out.print(list[i].get(j) + " ");
                }
                System.out.println();
            }
        }
    }

    public static void main(String[] args) {
        AdjacencyList adl = new AdjacencyList(4);
        adl.addEdge(0,1);
        adl.addEdge(1,2);
        adl.addEdge(2,3);
        adl.printGraph();
    }

} 

上面的输出如下所示:

节点 0 连接到:1
节点 1 连接到:2 0
节点 2 连接到:3 1
节点 3 连接到:2

结论

  • 我们学习了如何在编程中通过邻接矩阵和邻接表来表示图。


其他

哈希表数据结构

原文:https://www.studytonight.com/advanced-data-structures/hash-table-data-structure

哈希表是一种数据结构,用于存储键值对中的数据。

  • 哈希表中的每个键都映射到哈希表中的一个值。

  • 哈希表中的键用于索引值,因为我们获取这个键并将其传递给哈希函数,哈希函数又对其执行一些算术运算。操作后得到的结果值是哈希表的索引,我们在该表中存储键-值对。

  • 在内部,哈希表包含桶,特定键使用哪个桶的位置由键的哈希函数决定。

考虑下面的视觉表示:

Hash Table data structure

散列表的组成部分

哈希表总共包含两个部分,它们是:

哈希函数:

  • 散列函数用于确定键值对的索引。

  • 总是建议我们应该选择一个好的哈希函数来创建一个好的哈希表。

  • 除了一个好的散列函数之外,它应该是一个单向函数,即我们应该能够从密钥中获得散列值,而不是相反。

  • 此外,它应该避免为不同的密钥生成相同的哈希。

数组:

  • 数组(桶)用于保存键值对。

  • 数组的大小应该根据我们将拥有的键值对的数量来设置。

直接定址

这是一种我们利用直接地址表来映射值和它们的键的技术。它使用关键字作为存储桶的索引,然后将值存储在这些存储桶位置。虽然直接寻址确实有助于快速搜索、快速插入和快速删除操作,但这是有代价的。

考虑下面的图示:

Direct Address Table picture

直接地址表的优点:

  • O(1)时间插入 T4:在直接地址表中插入元素与在数组中插入元素相同,因此我们可以在 O(1)时间插入元素,因为我们已经知道了索引(通过键)。

  • 删除于O(1)时间:从直接地址表中删除一个元素与从数组中删除相同,因此时间为O(1)

  • O(1)时间内搜索:搜索一个元素需要线性时间 ( O(1) ) 因为如果我们已经知道一个元素的索引,我们可以很容易地在线性时间内访问该元素。

直接地址表的缺点:

  • 如果键值非常大,不建议使用直接地址表。

  • 它不能处理两个键相等并且包含不同数据的情况。

散列表

直接寻址有严重的缺点,使得它不适合当前世界场景的实际使用,这就是为什么我们使用哈希表。与直接地址表不同,在直接地址表中,我们将键作为地址表的索引,我们以不同的方式使用键。我们通过一个散列函数来处理这些密钥,我们从中得到的结果基本上就是存储数据的桶的位置。哈希表在不同的语言中有不同的实现,比如在 Java 中我们有哈希表哈希表等等,在 python 中我们有字典,但是不管它们是如何实现的,核心功能都是一样的。

考虑下面的图示:

Hash Table data structure

哈希表的优点:

  • 当我们谈到元素的插入删除搜索时,哈希表的优势是相同的,但是哈希表比地址表有一个巨大的优势,那就是它保持了大小约束。让我们考虑一个键= 7898789 ,这又是一个很大的数字,如果我们将它插入到一个直接地址表中,那么我们就是浪费了太多的空间,因为我们将不得不找到这个位置(键),然后在那个位置插入值,但是在哈希表的情况下,我们可以通过一个哈希函数处理这个键,假设它产生我们= 17,现在我们只剩下在哈希表的位置(17)插入。

哈希表的缺点:

  • 当我们通过哈希函数为不同的键获取相同的桶位置时,可能会出现一种情况,这种情况称为冲突。虽然我们可以提高哈希质量,但我们不能保证不会发生冲突。

处理哈希表中的冲突:

我们有多种方法可以处理冲突。其中一些是:

一个好的散列函数:

一个好的散列函数可以同时代表许多东西,但是我们可以得出这样的结论:散列函数被认为是一个好的散列函数,如果:

  • 它尽可能减少碰撞的数量。

  • 它不应该生成比哈希表更大的桶位置,在这种情况下,我们将浪费太多的空间。

  • 生成的铲斗位置既不能相距太远,也不能太近。

线性探测:

这是一种技术,可以确保如果我们在某个特定的桶上发生了冲突,那么我们会检查下一个可用的桶位置(就在它的下面),并将我们的数据插入到那个桶中。

考虑如下所示的图示:

Linear Probing

二次探测:

在二次探测中,使用以下公式确定下一个铲斗位置: h(k,i) = (h?(k) + xi + yi^2) 其中xy是常量。另一种观点认为,下一个位置之间的距离是二次增加的。

考虑如下所示的图示:

Quadratic Probing

链接:

在这种冲突处理技术中,如果在一个特定的桶位置发生冲突,那么在该位置我们只需创建一个链表,该值将被添加为该列表的下一个节点。哈希表变成链表的数组。

考虑如下所示的图示:

Chaining

哈希表的应用:

模式匹配:

哈希表搜索时间的复杂度使其成为在字符串池中寻找模式的完美候选。

编译器:

编译器利用哈希表存储关键字和其他标识符来存储编程语言的值。

文件系统:

我们的文件系统中的文件名和该文件的路径之间的映射是通过一个映射来存储的,该映射利用了一个哈希表。

结论

  • 我们了解了哈希表是什么,它的主要组成部分是什么。

  • 然后我们学习了直接地址表,接下来是哈希表的详细解释。

  • 然后我们讨论了处理哈希表中冲突的不同技术,接着是哈希表的实际应用。