Q1. 快速排序和冒泡排序有了解吗?
冒泡排序的思想:n个数据最多进行n-1次冒泡,每次冒泡都会将未排序的最大值移动到未排序序列末尾,冒泡方式是从左到右一次两两比较,将值较大的交换到右侧。每次冒泡选出最大值放到争取的位置。时间复杂度O(n2)
冒泡排序的优化:在一次冒泡中没有发生变化,说明整个序列有序,不需继续遍历,退出循环。
代码
#include<iostream>
using namespace std;
void swap(int*a, int*b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void bubblesort(int* data, int length)
{
if (data == nullptr||length<=0)
return;
for (int j = 1; j < length; ++j)//冒泡n-1次
{
bool flag = false;
for (int i = 0; i < length-i; ++i)//一次冒泡
{
if (data[i + 1] < data[i])
{
flag = true;
swap(&data[i + 1], &data[i]);
//int temp = data[i + 1];
//data[i + 1] = data[i];
//data[i] = temp;
}
}
if (!flag)
break;
}
return;
}
int main()
{
int data[7] = { 6, 2, 1, 4, 7, 5, 3 };
bubblesort(data, 7);
for (int i = 0; i < 7; ++i)
{
cout << data[i] << endl;
}
return 0;
}
快速排序的思想:基于分治策略。最好的情况时间复杂度为O(n),最差为O(n2),平均为O(nlogn)
1.划分:选取一个元素作为基准元素,以基准元素为界,左侧子序列都比它小,右侧序列都比它大。左右指针开始时分别指向序列两端,先从右向左扫描,找小于等于基准元素的数,赋给左指针所在的位置,再从左向右扫描,找大于基准元素的数,赋给右指针所在的位置,每次赋值操作使得左指针指向已经找到的比基准数小的序列的最右端,右指针指向已经找到的比基准数大的序列的最左端,扫描交替进行直到指针相遇,相遇位置赋值为基准数,返回该位置。
2.递归:通过返回的位置将序列划分成两个子数组,通过递归调用对左右两个子序列进行排序,当子序列为空,或者只有一个元素的时候,递归结束。
代码
#include<iostream>
using namespace std;
//void swap_element(int *a, int *b)
//{
// int temp;
// temp = *a;
// *a = *b;
// *b = temp;
//}
//另外一种分割算法
//int Partition(int data[], int length, int start, int end)
//{
// if (data == NULL || length <= 0 || start<0 || end >= length)
// {
// cout << "error1!" << endl;
// exit(0);
// }
// //int index = RandomInRange(start, end);
// //int index = end;
// //swap_element(&data[index], &data[end]);
// int small = start - 1;
// for (int index = start; index<end; index++)
// {
// if (data[index]<data[end])
// {
// ++small;
// if (small != index)
// {
// swap_element(&data[index], &data[small]);
// }
// }
// }
// ++small;
// swap_element(&data[small], &data[end]);
// return small;
//}
int partition(int* data, int start, int end)
{
int temp = data[start];//基准数
int i = start;
int j = end;
while (i < j)
{
while (i<j&&data[j]>temp)
--j;
data[i] = data[j];
while (i < j&&data[i] <= temp)
++i;
data[j] = data[i];
}
data[i] = temp;
for (int i = 0; i < 7; ++i)
cout << data[i] << ' ';
cout << endl;
return j;
}
void quicksort(int* data, int start, int end)
{
if (start >= end)
return;
int index = partition(data, start, end);
if (index < end)
quicksort(data, index + 1, end);
if (index>start)
quicksort(data,start,index-1);
}
int main()
{
int data[7] = { 6, 2, 1, 4, 7, 5, 3 };
quicksort(data, 0, 6);
for (int i = 0; i < 7; ++i)
cout << data[i] << ' ';
cout << endl;
return 0;
}
Q2. 类的对象在内存中的存储?
- 变量:提供一个具名的、可供程序操作的存储空间。
- 通常,对象是指一块能存储数据并具有某种类型的内存空间。
敲重点
在C++中,如果类中有虚函数,那么他就会有一个虚函数表的指针_vfptr
- 在类对象最开始的内存数据中,存放虚函数表指针。(注意:类对象不包含虚函数表,只有一个指向虚函数表的指针,类才包含虚函数表)
- 之后是类中的成员变量的内存数据。
对于子类
- 最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。
- 之后是子类自己的成员变量数据。
对于子类的子类,也是同样的原理。但是无论继承了多少个子类,对象中始终只有一个虚函数表指针。(多继承时有多个虚指针)
函数成员不占用内存中类的对象的字节
结论:
(1)对于基类,如果有虚函数,那么先存放虚函数表指针,然后存放自己的数据成员;如果没有虚函数,那么直接存放数据成员。
(2)对于单一继承的类对象,先存放父类的数据拷贝(包括虚函数表指针),然后是本类的数据。
(3)虚函数表中,先存放父类的虚函数,再存放子类的虚函数 。(4)如果重载了父类的某些虚函数,那么新的虚函数将虚函数表中父类的这些虚函数覆盖。
(5)对于多重继承,先存放第一个父类的数据拷贝,在存放第二个父类的数据拷贝,一次类推,最后存放自己的数据成员。其中每一个父类拷贝都包含一个虚函数表指针。如果子类重载了某个父类的某个虚函数,那么该将该父类虚函数表的函数覆盖。另外,子类自己的虚函数,存储于第一个父类的虚函数表后边部分。
(6)对于单一虚继承,会保存两个虚表指针。子类的内存中,首先是自己的虚函数表,然后是子类的数据成员,然后是0x0,之后就是父类的虚函数表,之后是父类的数据成员。如果子类重载了父类的虚函数,那么则将子类内存中父类虚函数表的相应函数替换。
(7) 对于菱形虚继承,会先保存第一个直接基类的拷贝,然后保存第二个直接基类的拷贝,然后保存子类的数据成员,最后才保存间接基类的虚表指针和数据成员。子类的虚函数保存在第一个直接基类的虚表中
Q3:给两个目录找差异(文件、目录)
(づ ̄3 ̄)づ╭❤~
Q4:有自己做过数据结构吗
Q5:未来规划