1.函数指针的假引用问题:
int test(int a, int b)
{
return a + b;
}
int main()
{
int(*ptr)(int, int) = test;
//这里所要说明的就是test前面加不加&,都一样
printf("%d", (*ptr)(1, 2));
//(ptr)前面加不加*也都一样,甚至(***********ptr)也都没有问题ptr(1,2)也没问题
return 0;
}
//但是又牵扯出一个问题就是函数实际是在运行的时候才进行空间的分配的,但是int(*ptr)(int, int) = test这里test还没有空间,
//那这里分配的又是什么东西?
//每个函数背后都有一张符号表,然后符号表里面记录着函数的虚地址,在函数运行的时候,就会临时的把虚地址个运行时函数的实地址关联起来
//所以说函数指针是一个假指针,所以说&,* 都是假的,加不加都可以
单列结构体:
struct
{
int a;
int b;
}point = { 1, 2 };
//这个结构体并没有名字,只是在最后的位置定义了了一个变量,并且附上了初始,这个叫单例结构体,
//后面的话就可以应用单例变量里面的内容。
尾递归:
void test(int n)
{
if(n <= 2)
return 1;
return test(n-1)+test(n-2);
//这个是求斐波拉契数列的递归算法
}
//不属于尾递归
//递归求阶乘,这个属于尾递归,尾递归指的就是,函数在末尾已经结束后才开始第二次调用,这样就不会存在爆栈,
//记住上一次运行的结果,然后在原来的栈中进行第二次函数的运算就属于尾递归
void test(int n)
{
if(n==1)
return 1;
return n*test(n-1);
}
但是尾递归很鸡肋,能用尾递归的就一定可以使用循环,只有到不得不使用递归的时候才会使用,比如树的暴力搜索。
优化冒泡排序:
void bubblesort(int *a,int length)
{
int flag; //设置一个标识位,来判断是否在冒泡的过程中发生了交换
for (int i = 0; i < length - 1; ++i)
{
flag = 0; //冒泡过程中的每一趟都要进行置零
for (int j = 0; j < length - i - 1; ++j)
{
if (a[j]>a[j + 1])
{
swap(a[j], a[j + 1]);
flag = 1; //如果某趟冒泡过程中发生交换,则把标志位设为1
}
}
if (flag == 0) //每一趟冒泡完毕判断标志位是否发生变化
return;
}
}
删除数组中的重复元素
但是删除之后需要把数组的长度也传出去,不然的话index后面存的是垃圾数,最后打印的话也会打印出来。
//删除一个数组中重复的元素,要求时间复杂度为0(n),空间复杂度为0(1)
void pop_equal_number(int *a, int length,int number)
{
int index = 0;
for (int i = 1; i < length; ++i)
{
if (a[i] != number)
{
a[index] = a[i];
index++;
}
}
}
//这里需要注意的就是加入要在外部打印,这里的数组长度需要更新,不然就会打印出垃圾值
删除链表中给定的元素;
删除链表中给定的元素,需要考虑的就是内存的释放,不然会引起内存泄漏。
也就是说线性表说说的删除其实是覆盖,而链表实际上是 删除那一块内存。
//这里采用的是两个指针,一个指针始终在另一个指针的前面一个位置来进行循环的。
struct ListNode
{
int val;
struct ListNode* next;
};
struct ListNode* removeElements(struct ListNode* head, int number)
{
//首先我们为了避免特殊情况,刚开始就是两个连续的需要删除的数据,我们先不考虑第一个,到最后再回过头来看。
ListNode* p = head;
ListNode* p2 = head->next;
while (p2 != nullptr)
{
if (p2->val == number)
{
p->next = p2->next;
delete p2;
p2 = p->next;
}
else
{
p = p2;
p2 = p2->next;
}
}
if (head->val == number)
{
ListNode* p = head;
head = head->next;
delete p;
}
return head;
}