1.什么是递归
简单的来说递归就是一个函数直接或间接地调用自身,是为直接或间接递归。一般来说,递归需要有边界条件、递归前进段和递归返回段(其实就是进栈出栈的操作)。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。用递归需要注意以下两点:(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
递归一般用于解决三类问题:
(1)数据的定义是按递归定义的。(Fibonacci函数,n的阶乘)
(2)问题解法按递归实现。(回溯)
(3)数据的结构形式是按递归定义的。(二叉树的遍历,图的搜索)
递归的缺点:
递归解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,因此递归次数过多容易造成栈溢出。
2.链表
不用STL库的链表初始化:
struct node { //用结构体变量和指向结构体变量的指针构成链表
int num;
struct node *next; //*next表示指向node这个结构体的指针变量
};
int main() {
node a, b, c, * head, * p;
a.num = 1;
b.num = 2;
c.num = 3;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;
while (head!=NULL) //遍历链表
{
std::cout << head->num << std::endl;
head=head->next; //指针指向下一个结构体
}
}
功能:将数据进行链式存储
链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
链表的组成:链表由一系列结点组成
结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域
STL中的链表是一个双向循环链表
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器
list的优点:
-
采用动态存储分配,不会造成内存浪费和溢出
-
链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
list的缺点:
-
链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大
List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。
总结:STL中List和vector是两个最常被使用的容器,各有优缺点
2.1创建链表
-
list<T> lst;
//list采用采用模板类实现,对象的默认构造形式:
list<int>L1;
-
list(beg,end);
//构造函数将[beg, end)区间中的元素拷贝给本身。
list<int>L2(L1.begin(),L1.end());
-
list(n,elem);
//构造函数将n个elem拷贝给本身。
list<int>L4(10, 1000);
-
list(const list &lst);
//拷贝构造函数。
list<int>L3(L2);
2.2 给链表赋值和交换
-
assign(beg, end);
//将[beg, end)区间中的数据拷贝赋值给本身。
L3.assign(L2.begin(), L2.end());
-
assign(n, elem);
//将n个elem拷贝赋值给本身。
L4.assign(10, 100);
-
list& operator=(const list &lst);
//重载等号操作符
L2 = L1;
-
swap(lst);
//将lst与本身的元素互换。
L1.swap(L2);
3.3 对list容器的大小进行操作
-
size();
//返回容器中元素的个数
L1.size()
-
empty();
//判断容器是否为空
L1.empty()//是空返回1
-
resize(num);
//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除。
L1.resize(10);
-
resize(num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 //如果容器变短,则末尾超出容器长度的元素被删除。
总结:
-
判断是否为空 --- empty
-
返回元素个数 --- size
-
重新指定个数 --- resize
3.4 list 插入和删除
-
push_back(elem);//在容器尾部加入一个元素
L.push_back(10);
-
pop_back();//删除容器中最后一个元素
L.pop_back();
-
push_front(elem);//在容器开头插入一个元素
L.push_front(100);
-
pop_front();//从容器开头移除第一个元素
L.pop_front();
-
insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
list<int>::iterator it = L.begin();
L.insert(++it, 1000);
-
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
-
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
-
clear();//移除容器的所有数据
-
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
-
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
it = L.begin();
L.erase(++it);
-
remove(elem);//删除容器中所有与elem值匹配的元素。
L.push_back(10000);
L.push_back(10000);
L.push_back(10000);
L.remove(10000);
总结:
-
尾插 --- push_back
-
尾删 --- pop_back
-
头插 --- push_front
-
头删 --- pop_front
-
插入 --- insert
-
删除 --- erase
-
移除 --- remove
-
清空 --- clear
3.5 list 数据存取
-
front();
//返回第一个元素。
cout << "第一个元素为: " << L1.front() << endl;
-
back();
//返回最后一个元素。
cout << "最后一个元素为: " << L1.back() << endl;
遍历
void printList(const list<int>& L) {
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
总结:
-
list容器中不可以通过[]或者at方式访问数据
-
返回第一个元素 --- front
-
返回最后一个元素 --- back
3.6 list 反转和排序
-
reverse();
//反转链表
L.reverse();
-
sort();
//链表排序
L.sort(); //默认的排序规则 从小到大
L.sort(myCompare); //指定规则,从大到小
4. 从尾到头打印链表
方法一:利用递归: 先走至链表末端,回溯时依次将节点值加入列表 ,这样就可以实现链表值的倒序输出
#include<iostream>
struct node { //用结构体变量和指向结构体变量的指针构成链表
int num;
struct node *next; //*next表示指向node这个结构体的指针变量
};
class Solution {
public:
void reversePrint(node *head) {
// while (head!=NULL) {
// std::cout << head->num << std::endl;
// head=head->next;
// }
// 1 2 3 先将指针指向链表的最后一个,然后再一个一个递归出 3 2 1
if (head == NULL)
{
return; //递归完毕,一个一个弹出,每弹出一个执行一次cout显示从尾到头
}
if (head != NULL)
{
reversePrint(head->next); //一个一个将指针往后移直到最后一个
}
std::cout << head->num << std::endl;
}
};
int main() {
node a, b, c, * head, * p;
a.num = 1;
b.num = 2;
c.num = 3;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;
Solution test;
test.reversePrint(p);
}
方法二:辅助栈法:
解题思路:
链表特点: 只能从前至后访问每个节点。
题目要求: 倒序输出节点值。
这种 先入后出 的需求可以借助 栈 来实现。
#include<iostream>
#include<stack>
struct node { //用结构体变量和指向结构体变量的指针构成链表
int num;
struct node *next; //*next表示指向node这个结构体的指针变量
};
class Solution {
public:
void reversePrint(node* head) {
std::stack<int> temp;
while (head != NULL)
{
temp.push(head->num);
head = head->next;
}
while (!temp.empty())
{
std::cout << temp.top() << std::endl;
temp.pop();
}
}
};
int main() {
node a, b, c, * head, * p;
a.num = 1;
b.num = 2;
c.num = 3;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;
Solution test;
test.reversePrint(p);
}
方法三:利用STL list库的sort
#include<iostream>
#include<list>
bool myCompare(int val1, int val2)
{
return val1 > val2;
}
int main() {
std::list<int> list;
list.push_back(0);
list.push_back(2);
list.push_back(3);
a.printList(list);
list.sort(myCompare);
a.printList(list);
}