笔试-笔记2

1.设存在函数int max(int,int)返回两参数中较大值,若求22,59,70三者中最大值,下列表达式不正确的是()

A.int m=max(22,59,70);

B.int m=max(22,max(59,70));

C.int m=max(max(22,59),70);

D.int m=max(59,max(22,70));

解析:

考察对函数参数的理解,很简单,选择不正确的,选A

2.在哪种派生方式中,派生类可以访问基类中的protected成员()

A.仅protected

B.public和private

C.public和protected

D.protected和private

解析:

题目错了,说一下涉及的知识。

  • 在派生类内,也就是派生类的成员函数里无论是public公有继承,还是private私有继承,还是protected保护继承,都是可以访问基类中的protected成员 ,且可以修改
    像这样:
cpp 复制代码
// 基类
class Base {
protected:
    int protectedVar;

public:
    Base(int val) : protectedVar(val) {}

    void displayBase() {
        cout << "Base protectedVar: " << protectedVar << endl;
    }
};

// 派生类,使用 public 派生
class DerivedPublic : public Base {
public:
    DerivedPublic(int val) : Base(val) {}//修改基类的保护成员

    void displayDerived() {
        cout << "DerivedPublic protectedVar: " << protectedVar << endl;
    }
};

// 派生类,使用 protected 派生
class DerivedProtected : protected Base {
public:
    DerivedProtected(int val) : Base(val) {}//修改基类的保护成员

    void displayDerived() {
        cout << "DerivedProtected protectedVar: " << protectedVar << endl;
    }
};

// 派生类,使用 private 派生
class DerivedPrivate : private Base {
public:
    DerivedPrivate(int val) : Base(val) {}//修改基类的保护成员

    void displayDerived() {
        cout << "DerivedPrivate protectedVar: " << protectedVar << endl;
    }
};
  • 在派生类外,也就是用派生类对象访问,只有public继承的父类public成员才可以访问和修改,
    比如像下面这样(接着上面例举的三个类):
cpp 复制代码
int main() {
    DerivedPublic dp(10);
    cout<<dp.protectedVar;//会报错,无法访问,
    return 0;
}

当然这也是无法直接访问,如果用派生类对象调用成员函数访问或修改还是可以的,如下:

cpp 复制代码
int main() {
    DerivedPublic dp(10);
    dp.displayDerived();  // 输出: DerivedPublic protectedVar: 10

    DerivedProtected dpro(20);
    dpro.displayDerived();  // 输出: DerivedProtected protectedVar: 20

    DerivedPrivate dpri(30);
    dpri.displayDerived(); // 输出: DerivedProtected protectedVar: 30

    return 0;
}

3.有关函数重载的正确说法是()

A.函数名相同,但参数的个数不同或参数的类型不同

B.函数名相同,函数的返回值不同,而与函数的参数和类型无关

C.函数名相同,参数的个数和类型相同

D.函数名不同,但参数的个数和类型相同

解析:

  • 重载与函数返回值无关,只与参数有关,选A

4.下列正确声明中为纯虚函数的是()

A.virtual void fun()=0;

B.void virtual fun()=0;

C.void virtual fun();

D.virtual void fun();

解析:

  • 只有包含 virtual 关键字并在函数声明末尾加上 = 0 的函数才是纯虚函数。纯虚函数是没有函数体的,选A
  • 末尾没有=0的,比如D是虚函数。

5.下列程序的输出结果是()

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
    int n[][3]={10,20,30,40,50,60};
    int *p=&n[0][0];
    cout<<*p<<","<<*(p+1)<<endl;
    return 0;
}

A.40,20

B.40,21

C.10,21

D.10,20

解析:

  • 这里指针p指向的是n[0][0]也就是10,指针p不是数组指针,所以*(p+1)也就是列坐标加1,也就是n[0][1],也就是20,选D
  • 数组指针是这样,如下:
cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
    int n[2][3]={10,20,30,40,50,60};
    int (*p)[3]=n;
    cout<<**p<<","<<**(p+1)<<endl;
    return 0;
}

6.为了提高程序的运行速度,可将不太复杂的功能用函数实现,此函数应选择()

A.递归函数

B.重载函数

C.内联函数

D.函数模板

解析:

  • 选C,内联函数是一种在C/C++中用于提高程序运行效率的机制。内联函数的基本思路是将函数的代码直接插入到调用它的地方,而不是通过函数调用的方式执行。这样可以减少函数调用的开销,从而提高程序的运行速度。
  • 内联函数的关键字为inline,示例如下:
cpp 复制代码
inline int add(int a, int b) {
    return a + b;
}
  • 说下函数模板是C++中的一种泛型编程机制,允许你编写一个通用的函数,可以处理不同类型的参数。函数模板使得你可以编写一次代码,然后在不同的情况下使用不同的数据类型,而不需要为每种数据类型编写单独的函数。
    函数模板的定义:
    函数模板的定义使用template关键字,后面跟着模板参数列表。模板参数列表用尖括号<>包围,其中可以包含一共或多个类型参数(通常用 typename 或 class 关键字声明)。如下示例:
cpp 复制代码
template <typename T>
T add(T a, T b) {
    return a + b;
}

7.float类型的变量a=0.6,以下float变量可以认为和a相当的是()

A.其他三个选项都不是

B.b=1-1/2

C.b=1-0.5

D.b=1/2

解析:

  • 我选的是A,没看懂这题的意思是相等,还是与a最接近的,与a最接近的话,那就选C.

  • 说下那三个选项的结果吧,1-1/2=1,1-1.0/2=0.5,1/2=0

8.int(*fun[10])(int)中fun表示的是什么()

A.函数指针数组,每个指针指向一个int func(int param)的函数

B.指针数组,每个指针指向长度为1的int数组

C.函数指针数组,每个指针指向一个int func(int* param)的函数

D.指针数组,每个指针指向长度为10的int数组

解析:

  • 选A,(*fun[10]) 表示数组的每个元素是一个指针,int(*fun[10])(int) 表示每个指针指向一个函数,该函数的返回类型是 int,并且接受一个 int 类型的参数.
  • 给个示例如下:
cpp 复制代码
#include <iostream>

// 定义一些示例函数
int addOne(int x) {
    return x + 1;
}

int multiplyByTwo(int x) {
    return x * 2;
}

int subtractThree(int x) {
    return x - 3;
}

int main() {
    // 定义函数指针数组
    int (*fun[10])(int);

    // 初始化函数指针数组
    fun[0] = addOne;
    fun[1] = multiplyByTwo;
    fun[2] = subtractThree;

    // 使用函数指针数组
    int result1 = fun[0](5); // 调用 addOne(5)
    int result2 = fun[1](5); // 调用 multiplyByTwo(5)
    int result3 = fun[2](5); // 调用 subtractThree(5)

    // 输出结果
    std::cout << "Result of addOne(5): " << result1 << std::endl;
    std::cout << "Result of multiplyByTwo(5): " << result2 << std::endl;
    std::cout << "Result of subtractThree(5): " << result3 << std::endl;

    return 0;
}

9.若obj是类D的对象,则下列语句中正确的是()

cpp 复制代码
class B{
private:
    void fun1(){}
protected:
    void fun2(){}
public:
    void fun3(){}
};
class D:public B{
protected:
    void fun4(){}
};

A.obj.fun3();

B.obj.fun2();

C.obj.fun4();

D.obj.fun1();

解析:

  • 选A,在类外也就是对象调用,只能调用自己公有成员函数,fun4()是保护成员函数,也无法调用基类的私有成员函数和保护成员函数,只有在公有继承下能调用基类的公有成员函数。

10.如没有private关键字定义类的数据成员,则默认为()

A.public

B.protected

C.private

D.friend

解析:

  • 默认为私有,选C
  • friend 是 C++ 中的一个关键字,用于声明友元。友元机制允许一个类或函数访问另一个类的私有成员和保护成员。
  • 友元函数:一个非成员函数可以被声明为某个类的友元,从而可以访问该类的私有成员和保护成员。
    友元类:一个类可以被声明为另一个类的友元,从而该类的所有成员函数都可以访问另一个类的私有成员和保护成员。
    友元成员函数:一个类的特定成员函数可以被声明为另一个类的友元,从而该成员函数可以访问另一个类的私有成员和保护成员。

11.sizeof和strlen的区别是()

A.sizeof和strlen都可以用于计算数组,数据类型和字符串的大小或长度

B.sizeof用于计算字符串的长度,而strlen用于计算数组或数据类型的大小

C.sizeof用于计算数组或数据类型的大小,而strlen用于计算字符串的长度

D.sizeof和strlen是相同的,可以互相使用

解析:

  • 选C,strlen只能计算字符串长度

12.下面关于继承和派生的构造函数和析构函数的程序,输出结果是()

cpp 复制代码
#include<iostream>
using namespace std;
class AA{
public:
    AA() {cout<<'A';}
    ~AA() {cout<<'a';}
};
class BB:public AA{
    AA aa;
public:
    BB() {cout<<'B';}
    ~BB() {cout<<'b';}
};
int main()
{
    BB bb;
    return 0;
}

A.AABbaa

B.BAAaab

C.AABaab

D.BAAbaa

解析:

  • 派生类创建对象,单继承时,派生类构造函数总是先调用基类构造函数再执行其他代码,
  • 如题,那么创建bb对象时,会先执行一次AA类的构造函数,输出一个A,在BB类中会创建AA类的对象,这时又会输出A,然后到BB类的构造函数,输出一个B,然后到析构也就是bb对象的删除,输出一个b,然后是对象aa的析构,输出一个a,再到调用基类AA的析构,再输出一个a,结果就是AABbaa,选A

13.一个栈的入栈序列是A,B,C,D,E,则栈的不可能的输出序列是()

A.E D C B A

B.A B C D E

C.D C E A B

D.D E C B A

解析:

  • 选C,A选项是全入栈,然后出栈,因为后进先出,
  • B选项是一入栈就出栈
  • C选项不可能,C选项也就是先ABCD入栈,出D,再出C,E入栈再出栈,然后栈内就剩BA,出栈顺序也只能是BA,顺序只有可能是DCEBA
  • D选项是可以的

14.若希望当A的值为奇数时,表达式的值为"真",A的值为偶数时,表达式的值为"假"。则以下不能满足要求的表达式是()

A.!(A/2)

B.A%2

C.A/2

D.!(A%2)

解析:

  • A的值是整数,!(A/2)中A无论是奇数,还是偶数,都无法判断,
  • B是可以满足
  • C也不行
  • D可以
  • 这题选A,C

15.对于指针的运算,下列说法正确的是()

A.两个指针在一定条件下,可以进行相等或不相等的运算

B.两个指针可以进行加法运算

C.一个指针可以加上一个整数

D.可以用一个空指针赋值给某个指针

解析:

  • 选A,C,D,两个指针相加有些情况可能会不合法

16.关于派生类的说法不正确的是()

A.派生类可以拥有自己的新成员

B.派生类无法给基类的数据成员初始化

C.派生类可重载已有的函数成员

D.派生类可显现基类的任何函数成员

解析:

  • A,B,C都是正确的,派生类中不能访问基类中的私有成员
  • 派生类重载基类有两种方法,一种通过using在派生类中为父类函数成员提供声明,另一种是通过基类指针,也可以定义成虚函数的方式,如下:
cpp 复制代码
#include <iostream>

// 基类
class Base {
public:
    // 基类的成员函数
    void display() {
        std::cout << "Base class display()" << std::endl;
    }

    // 基类的另一个成员函数,参数不同
    void display(int x) {
        std::cout << "Base class display(int x): " << x << std::endl;
    }
};

// 派生类
class Derived : public Base {
public:
    // 使用 using 声明引入基类的 display 函数
    using Base::display;

    // 派生类重载基类的成员函数
    void display() {
        std::cout << "Derived class display()" << std::endl;
    }

    // 派生类重载基类的另一个成员函数,参数不同
    void display(int x, int y) {
        std::cout << "Derived class display(int x, int y): " << x << ", " << y << std::endl;
    }
};

int main() {
    Derived d;

    // 调用派生类的成员函数
    d.display();          // 输出: Derived class display()
    d.display(10);        // 输出: Base class display(int x): 10
    d.display(20, 30);    // 输出: Derived class display(int x, int y): 20, 30
    // 调用派生类的成员函数
    // //基类指针的方式
    // Derived d;
    // Base *x=&d;
    // // 调用派生类的成员函数
    // x->display();          // 输出: Derived class display()
    // x->display(10);        // 输出: Base class display(int x): 10
    // d.display(20, 30);    // 输出: Derived class display(int x, int y): 20, 30


    return 0;
}
  • 选D,D是错的

17.下面描述正确的是()

A.析构函数不可以继承

B.构造函数可以继承

C.派生类成员函数继承不构成重载

D.基类成员函数继承构成重载

解析:

  • 选A,派生类继承基类是不会构成重载,只会覆盖。

18.下面函数原型中,不是纯虚函数的是()

A.virtual void fun()=0

B.virtual void fun()

C.virtual void fun() {}

D.void fun()=0

解析:

  • 只有A是纯虚函数,选BCD

19.对继承描述正确的是()

A.可以private继承

B.可以protected继承

C.可以public继承

D.多继承会导致从两个或更多基类那里继承同一个类的多个实例

解析:

  • 选ABCD

20.指出下面代码的错处()

cpp 复制代码
#include<iostream>
using namespace std;
class student{
public:
    int a;
    char b;
    string c;
protected:
    int d;
};
int main()
{
    student st;
    st.a='a';
    st.b="a";
    st.c="a";
    st.d=1;
    return 0;
}

A.st.b="a";

B.st.d=1;

C.st.a='a';

D.st.c="a";

解析:

  • 选AB,双引是字符串,不能赋给char类型,类外也就是对象不能访问protected成员。

21.关于group by 子句的作用描述正确的是()

A.可用于过滤数据

B.可用于sum

C.可用于avg

D.用于having子句

解析:

  • group by的作用是用于分组的,不能起到过滤数据的作用,用于过滤数据的是where。分组可以一组数据的和sum,也可以计算一组数据的平均数avg,having是过滤条件,是和分组搭配用的,
  • 选BCD

22.类B从类A派生(public),则类B可以访问类A中的()成员

A.protected成员

B.private成员

C.所有函数成员

D.public成员

E.所有数据成员

解析:

  • 可以访问公有public成员和保护protected成员
  • 选AD

23.对抽象类描述正确的是()

A.子类必须重写抽象类中的纯虚函数

B.无法实例化对象

C.当类中有了纯虚函数,这个类也称为抽象类

D.如果是纯虚析构,该类属于抽象类,无法实例化对象

解析:

  • 选ABCD.
  • 抽象类的特点:抽象类无法实例化对象,子类必须重写抽象类中的纯虚函数,否则也属于抽象类无法实例化对象

24.系统在调用函数时往往根据一些条件确定哪个函数被调用其中会有一些重载函数,在下列选项中,哪些可以作为区分不同函数的依据()

A.函数的返回值类型

B.函数名称

C.参数的类型

D.参数个数

解析:

  • 选BCD,函数名相同,返回值类型不同是非法的,会报错

25.关于下列操作()复杂度为O(1)

A.set中查找元素

B.vector中插入元素的最差情况

C.deque尾部删除元素

D.hash_map中查找元素

解析:

  • vector插入,该位置插入后后面的都要改变O(n)
  • set 底层红黑树 O(logn)
  • hast_map 底层哈希表 O(1)
  • deque尾部可以直接修改O(1)
  • 选CD

26.请简要说明C++中的多态性,并说明虚函数和纯虚函数的作用。

答案:

C++支持两种形式的多态性:

  • 第一种是编译时多态,称为静态联编。是指程序在编译前确定的多态性,是通过重载机制来实现的包括:函数重载和运算符重载。
  • 第二种是运行时多态,称为动态联编。是指必须在运行中才可以确定的多态性,是通过继承和虚函数来实现的。
  • 虚函数:允许派生类重写基类的函数,实现运行时多态性。
  • 纯虚函数:在基类中没有实现,必须在派生类中被重写,用于定义抽象类。
  • 上面就是答案了,下面是对虚函数和纯虚函数的讲解
  • 虚函数是 C++中实现运行时多态性的关键机制。通过在基类中将函数声明为虚函数,派生类可以重写(override)该函数,从而在运行时根据对象的实际类型调用相应的函数。示例如下:
cpp 复制代码
#include <iostream>
// 基类
class Base {
public:
    // 虚函数
    virtual void display() {
        std::cout << "Base class display()" << std::endl;
    }
};

// 派生类
class Derived : public Base {
public:
    // 重写基类的虚函数,关键字为override 
    void display() override {
        std::cout << "Derived class display()" << std::endl;
    }
};

int main() {
    Base* ptr;
    Derived d;

    // 基类指针指向派生类对象
    ptr = &d;

    // 调用派生类的 display 函数
    ptr->display();  // 输出: Derived class display()

    return 0;
}
  • 纯虚函数是一种特殊的虚函数,它在基类中没有实现,并且必须在派生类中被重写。包含纯虚函数的类称为抽象类(Abstract Class),不能直接实例化。
cpp 复制代码
#include <iostream>

// 抽象基类
class Shape {
public:
    // 纯虚函数
    virtual void draw() const = 0;
};

// 派生类:矩形
class Rectangle : public Shape {
public:
    // 重写纯虚函数
    void draw() const override {
        std::cout << "Drawing a rectangle" << std::endl;
    }
};

// 派生类:圆形
class Circle : public Shape {
public:
    // 重写纯虚函数
    void draw() const override {
        std::cout << "Drawing a circle" << std::endl;
    }
};

int main() {
    Shape* shapes[2];
    shapes[0] = new Rectangle();
    shapes[1] = new Circle();

    for (int i = 0; i < 2; ++i) {
        shapes[i]->draw();
    }

    // 释放内存
    delete shapes[0];
    delete shapes[1];

    return 0;
}

27.在设计网络服务器时,如何选择使用tcp/udp,如何根据应用场景选择,如何设计协议,多路复用机制如何选择?上述可以选择一个你擅长的方向进行做答。要求:选择tcp服务器时,要包含异步,多路复用,协议设计,链路管理,请写出关键步骤即可。选择UDP服务器时,要包含异步,多路复用,链路管理,尽可能快速,高效率发送数据。

解析:

  • TCP适用场景
    HTTP/HTTPS:网页浏览等场景,对数据完整性和顺序有严格要求。
    电子邮件(SMTP、POP3、IMAP):需要确保邮件的完整传输。
    文件传输(FTP):文件完整性非常重要,丢失数据将导致文件损坏。
  • UDP适用场景
    视频直播、在线游戏、语音通话(VoIP):对实时性要求高,即使丢失少量数据也不会严重影响体验。
    DNS:查询时无需连接,快速得到结果即可,无需保证数据可靠性。
    流媒体:音乐、视频的流式传输对数据到达的顺序和实时性有要求。
  • 异步处理是提高服务器性能的关键。通过异步处理,服务器可以在等待 I/O 操作完成的同时处理其他任务,从而提高并发处理能力。
  • 多路复用机制允许服务器同时监听多个连接,并在有数据到达时进行处理。常用的多路复用机制包括 epoll、kqueue 和 select。
  • 在 Linux 系统上,epoll 是首选,因为它支持大规模并发连接。
    在 BSD/macOS 系统上,kqueue 是更好的选择。
    select 虽然简单,但在高并发场景下性能较差。
  • 多路复用机制:创建一个事件循环(Event Loop),监听多个文件描述符(File Descriptors)。
    当有事件发生时(如新数据包到达),事件循环会通知应用程序进行处理。
  • 协议设计是确保服务器和客户端之间正确通信的关键。设计一个清晰、高效的协议可以减少数据传输的开销,提高通信效率。
  • 协议设计是确保服务器和客户端之间正确通信的关键。设计一个清晰、高效的协议可以减少数据传输的开销,提高通信效率。
    定义协议格式:(UDP是无连接协议)
    使用二进制格式或文本格式定义协议。二进制格式通常更高效,但文本格式更易于调试。
    定义消息头(Header)和消息体(Body),消息头包含消息类型、长度等信息,消息体包含实际数据。
    序列化和反序列化:
    使用高效的序列化和反序列化库(如 Protocol Buffers、FlatBuffers)来处理数据。
    确保序列化和反序列化过程高效且无错误。
  • 链路管理包括连接的建立、维护和关闭。有效的链路管理可以提高服务器的稳定性和性能。
  • TCP链路管理:
    连接建立:
    使用 accept 系统调用接受新连接,并将其添加到事件循环中进行管理。
    为每个连接分配一个唯一的标识符(如文件描述符),用于后续操作。
    连接维护:
    定期检查连接状态,处理超时连接。
    使用心跳机制(Heartbeat)保持连接活跃,防止连接因长时间无数据传输而被关闭。
    连接关闭:
    当连接不再需要时,使用 close 系统调用关闭连接。
    确保资源(如文件描述符、内存)被正确释放。
  • UDP链路管理:
    数据包接收:
    使用 recvfrom 系统调用接收数据包,并获取发送方的地址信息。
    将接收到的数据包放入处理队列中,以便后续处理。
    数据包发送:
    使用 sendto 系统调用发送数据包,指定目标地址。
    尽量减少数据包的大小,以提高传输效率。
    链路状态管理:
    在某些场景下,可能需要维护链路状态(如实时音视频传输)。
    使用心跳机制(Heartbeat)或序列号来检测数据包的丢失和重传。

28.[逻辑推理题]在一个村庄里,有三个人:A,B和C。他们中的两个人是骑士,一个人是小偷。一个骑士总是说真话,另一个骑士总是说谎话。以下是一些陈述:

A说:"B是小偷。"

B说:"我不是小偷"

C说:"A是小偷"

请确定谁是小偷并写出推理过程:

  • 如果A是说真话的骑士,那么C就是说假话的骑士,B是小偷,符合
  • 如果B是说真话的骑士,那么小偷在A,C之间,C不能是说假话的骑士,所以C是小偷
  • 如果C是说真话的骑士,不符合,B不能是说假话的骑士

29.[逻辑推理题]问题:A,B,C,D,E五个人参加比赛,并最后分别获得了第1,2,3,4,5名。以下是一些陈述:

A说他没有获得第1名

B说他获得了第3名

C说他不是第3名

D说他在B之前

E说他获得了第1名,

请确定每个人的名次:

答案:EDBCA

30.[编程题]编写一个程序,用链表实现插入,删除和查找操作,使其始终是顺序的,例如1,2,3,4,5,6......

参考代码:

C语言版:

c 复制代码
#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int data;
    struct node *next;
} Node, *Ptrnode;

void createList(Ptrnode *number) {//创建链表,也是插入元素
    Ptrnode p, q;
    int a;
    while (~scanf("%d", &a)) {
        q = (Ptrnode)malloc(sizeof(Node));
        q->data = a;
        q->next = NULL;

        // 如果链表为空或者新节点的值小于头节点的值
        if (*number == NULL || (*number)->data > a) {
            q->next = *number;
            *number = q;
        } else {
            p = *number;
            // 找到插入位置
            while (p->next != NULL && p->next->data < a) {
                p = p->next;
            }
            q->next = p->next;
            p->next = q;
        }
    }
}

void display(Ptrnode number) {//打印链表
    Ptrnode q = number;
    while (q != NULL) {
        printf("%d ", q->data);
        q = q->next;
    }
    printf("\n");
}
void deleteNode(Ptrnode *number,int value)//删除链表
{
    if(*number==NULL)
    return;
    Ptrnode p=*number,q;
    if(p->data==value)
    {
        *number=p->next;
        free(p);
        return;
    }
    while(p->next->data!=value&&p->next!=NULL)
    {
        p=p->next;
    }
    if(p->next)
    {
        q=p->next;
        p->next=p->next->next;
        free(q);
    }
    else
    {
        printf("未发现要删除的元素");
    }
}
Ptrnode selectNode(Ptrnode number,int value)//返回节点
{
    if(number==NULL)
    {
        return NULL;
    }
    Ptrnode p=number;
    if(p->data==value)
    {
        return p;
    }
    while(p->next->data!=value&&p->next!=NULL)
    {
        p=p->next;
    }
    if(p->next)
    {
        return p->next;
    }
    else
    {
        return NULL;
    }
}
int selectNode1(Ptrnode number,int value)//返回第几个节点
{
    if(number==NULL)
    {
        return -1;
    }
    Ptrnode p=number;
    int count=1;
    if(p->data==value)
    {
        return count;
    }
    while(p->next->data!=value&&p->next!=NULL)
    {
        count++;
        p=p->next;
    }
    if(p->next)
    {
        return count+1;
    }
    else
    {
        return 0;
    }
}
void freeList(Ptrnode *number)//清空链表
{
    while(*number!=NULL)
    {
        Ptrnode temp=*number;
        *number=(*number)->next;
        free(temp);
    }
}
int main() {
    Ptrnode number = NULL; // 初始化为NULL
    createList(&number);
    
    //deleteNode(&number,4);
    // 打印链表
    display(number);
    Ptrnode p=selectNode(number,4);
    int index=selectNode1(number,4);
    if(p==NULL)
    {
        printf("未查找到该元素");
    }
    // 释放链表内存
    freeList(&number);

    return 0;
}

C++:

cpp 复制代码
#include<iostream>
using namespace std;
typedef struct node{
    int data;
    struct node* next;
    // 构造函数,使用初始化列表初始化成员变量
    node(int value): data(value),next(nullptr) {}
}*Ptrnode,Node;
class SortedLinkedList{
private:
    Ptrnode head;
public:
    SortedLinkedList(): head(nullptr) {}
    
    //插入操作
    void insert(int value){
        Ptrnode p=new node(value);
        if(!head||head->data>value)
        {
            p->next=head;
            head=p;
        }
        else
        {
            Ptrnode q=head;
            while(q->next&&q->next->data<value)
            {
                q=q->next;
            }
            p->next=q->next;
            q->next=p;
        }
    }
    void deleteNode(int value)//删除节点
    {
        if(!head)
        return;
        Ptrnode p=head,q;
        if(p->data==value)
        {
            head=p->next;
            delete p;
            return;
        }
        while(p->next->data!=value&&p->next)
        {
            p=p->next;
        }
        if(p->next)
        {
            q=p->next;
            p->next=p->next->next;
            delete q;
        }
        else
        {
            cout<<"未发现要删除的元素"<<endl;
        }
    }
    Ptrnode selectNode(int value)//查找返回节点
    {
        if(!head)
        return nullptr;
        
        Ptrnode p=head;
        
        if(p->data==value)
        {
            return p;
        }
        while(p->next->data!=value&&p->next)
        {
            p=p->next;
        }
        if(p->next)
        {
            return p->next;
        }
        else
        {
            return nullptr;
        }
    }
    int selectNode1(int value)//查找返回节点为第几个
    {
        if(!head)
        {
            return 0;
        }
        Ptrnode p=head;
        int count=1;
        if(p->data==value)
        {
            return count;
        }
        while(p->next->data!=value&&p->next)
        {
            count++;
            p=p->next;
        }
        if(p->next)
        {
            return count+1;
        }
        else
        {
            return 0;
        }
    }
    bool selectNode2(int value){//返回bool变量节点是否存在
        Ptrnode p=head;
        while(p){
            if(p->data==value){
                return true;
            }
            p=p->next;
        }
        return false;
    }
    void display(){//打印链表
        Ptrnode p=head;
        while(p!=NULL)
        {
            cout<<p->data<<' ';
            p=p->next;
        }
        cout<<endl;
    }
    ~SortedLinkedList(){//析构,删除链表
        while(head)
        {
            Ptrnode temp=head;
            head=head->next;
            delete temp;
        }
    }
};
int main()
{
    SortedLinkedList number;
    int a;
    while(cin>>a)
    number.insert(a);
    //number.deleteNode(8);
    //Ptrnode p=number.selectNode(4);
    // if(p==NULL)
    // {
    //     cout<<"未查找到该元素"<<endl;
    // }
    // else
    // {
    //     cout<<p->data<<endl;
    // }
    // int index=number.selectNode1(4);
    // cout<<index<<endl;
    number.display();
    return 0;
}

31.[编程题]编写一个程序,可以输出一个数组中第二大的数字?

参考代码:

cpp 复制代码
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    set<int>number;
    int a;
    while(cin>>a)
    {
        if(a==0)
        break;
        number.insert(a);
    }
    cout<<*next(number.rbegin())<<endl;
    return 0;
}

32.[编程题]编程实现,开启三个线程,这3个线程的ID分别为A,B,C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC---,依次类推。

解析:

cpp 复制代码
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;//互斥锁,用于保护共享资源current
std::condition_variable cv;//条件变量,用于线程间的等待和通知
int current = 0;  // 当前应该执行的线程ID

void print_id(char id, int order) {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lock(mtx);//互斥锁
        cv.wait(lock, [id, order] { return current == order; });
        std::cout << id;
        current = (current + 1) % 3;  // 更新下一个应该执行的线程ID
        cv.notify_all();  // 通知所有等待的线程
    }
}

int main() {
    std::thread tA(print_id, 'A', 0);
    std::thread tB(print_id, 'B', 1);
    std::thread tC(print_id, 'C', 2);

    tA.join();
    tB.join();
    tC.join();

    std::cout << std::endl;
    return 0;
}
相关推荐
爱码小白19 分钟前
网络编程(王铭东老师)笔记
服务器·网络·笔记
CYBEREXP200821 分钟前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos
yuanbenshidiaos43 分钟前
c++------------------函数
开发语言·c++
yuanbenshidiaos1 小时前
C++----------函数的调用机制
java·c++·算法
LuH11241 小时前
【论文阅读笔记】Learning to sample
论文阅读·笔记·图形渲染·点云
tianmu_sama1 小时前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
羚羊角uou1 小时前
【C++】优先级队列以及仿函数
开发语言·c++
姚先生971 小时前
LeetCode 54. 螺旋矩阵 (C++实现)
c++·leetcode·矩阵
FeboReigns2 小时前
C++简明教程(文章要求学过一点C语言)(1)
c语言·开发语言·c++
FeboReigns2 小时前
C++简明教程(文章要求学过一点C语言)(2)
c语言·开发语言·c++