和我一起学C++之list<三>
2017-05-10 10:38
218 查看
接着上一章开始说。
我们知道对于一个数据结构来说,增删改查是最基本的操作。在上面的学习中,我们已经知道了怎样增改查了,所以下面我们来介绍下怎么删除一个节点
1、删除list中的节点
画图总是有助于我们分析的,所以直接上图看
与增加一个节点相反,我们只需要把待删除的节点的下一个节点的prev指针指向待删除节点的上一个节点,待删除节点的上一个节点的next指针指向待删除节点的下一个节点即可,然后再删除掉待删除节点本身。
2、删除list中的特定元素
利用我们之前的find函数和erase函数很容易就可以达到我们的目的
3、清空list中的元素
同样的,利用不断的erase第一个元素所在节点就可以达到我们的目的,如
但是这里还是有必要讲下对普通list(c-style)都适应的方法,包括单向和双向的链表。
通过上图我们知道,我们只需要先保存住第一个节点,然后将head哨兵的next指针指向第一个节点的下一个节点,再删除掉第一个节点即可。
4、pop_back 和 pop_front 操作
5、list中的排序问题
排序是笔试面试必考的内容之一,我们应该把每一种排序算法都烂熟于心。我们在这里这讲冒泡方法,当然我也会把STL中的算法给大家贴出来,供大家参考。
5.1、判断list是否有序
判读一个是不是无序的,只要判断是否存在一对相邻对是无序的即可。所以有
5.2 bubble 冒泡排序法
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
从上面的分析可以得到如下代码
上面的算法还可以进行改进,比如对如部分有序或者整体有序的序列,是不是还要经过这么多步的操作呢?
这个感兴趣的读者可以自行去查阅相关资料或者自己推导,可能后面我也会写一些排序的文章(没办法,太重要了)。
6、小测试
测试结果如下:
小结:本章主要讲了增删改查中删的相关操作和冒泡排序算法。在这章里,我们主要是通过图来分析思路,在实际过程中,借助画图和纸上计算是非常重要的辅助手段。在下一章里,将会讲到swap,merge,reverse等接口。
参考资料:
STL 源码剖析 侯捷著
数据结构(C++语言版)第三版 邓俊辉著
gcc 2.95 source code
https://zhuanlan.zhihu.com/p/24050357
我们知道对于一个数据结构来说,增删改查是最基本的操作。在上面的学习中,我们已经知道了怎样增改查了,所以下面我们来介绍下怎么删除一个节点
1、删除list中的节点
画图总是有助于我们分析的,所以直接上图看
与增加一个节点相反,我们只需要把待删除的节点的下一个节点的prev指针指向待删除节点的上一个节点,待删除节点的上一个节点的next指针指向待删除节点的下一个节点即可,然后再删除掉待删除节点本身。
list_iterator list::erase(list_iterator position) { if(position == end()) return end(); list_node* node_next = position.node_->next;//待删除节点的下一个节点 list_node* node_prev = position.node_->prev;//待删除节点的上一个节点 node_next->prev = node_prev; node_prev->next = node_next; delete position.node_;//删除待删除节点本身 position.node_ = nullptr; return list_iterator(node_next); }
2、删除list中的特定元素
利用我们之前的find函数和erase函数很容易就可以达到我们的目的
void list::remove(const int &value) { list_iterator it = find(begin(), end(),value); while (it != end())//找到该元素位置 { it = erase(it);//删除该元素所在节点,并返回其下一个节点位置 it = find(it, end(), value);//从删除节点下一个节点开始找 } }
3、清空list中的元素
同样的,利用不断的erase第一个元素所在节点就可以达到我们的目的,如
void list::clear() { auto it = begin(); while(it != end()) { it = erase(it); } }
但是这里还是有必要讲下对普通list(c-style)都适应的方法,包括单向和双向的链表。
通过上图我们知道,我们只需要先保存住第一个节点,然后将head哨兵的next指针指向第一个节点的下一个节点,再删除掉第一个节点即可。
void list::clear() { if (tail_ && head_) { while ( head_->next != tail_) { list_node *tmp = head_->next;//保存原第一个节点 head_->next = tmp->next;//新第一个节点 delete tmp;//删除原第一个节点 tmp = nullptr; } tail_->prev = head_; head_->next = tail_; } }
4、pop_back 和 pop_front 操作
void list::pop_back() { list_iterator tmp = end(); erase(--tmp); } void list::pop_front() { erase(begin()); }
5、list中的排序问题
排序是笔试面试必考的内容之一,我们应该把每一种排序算法都烂熟于心。我们在这里这讲冒泡方法,当然我也会把STL中的算法给大家贴出来,供大家参考。
5.1、判断list是否有序
判读一个是不是无序的,只要判断是否存在一对相邻对是无序的即可。所以有
bool list::unsorted() { //如果空list或者只有1个元素,返回true if (empty() || head_->next->next == tail_) return true; list_node* curr = head_->next; while(curr != tail_->prev) { if(curr->value > curr->next->value) return true; curr = curr->next; } return false; }
5.2 bubble 冒泡排序法
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
从上面的分析可以得到如下代码
void list::sort() { // 如果为空list或者只有1个元素,直接退出 if (empty() || head_->next->next == tail_) return; list_node *node1 = head_->next;// 外层循环 while (node1 != tail_) { list_node* node2 = head_->next;//内层循环 while (node2 != tail_->prev) { if (node2->value > node2->next->value) { int tmp = node2->value; node2->value = node2->next->value; node2->next->value = tmp; } node2 = node2->next; } node1 = node1->next; } }
上面的算法还可以进行改进,比如对如部分有序或者整体有序的序列,是不是还要经过这么多步的操作呢?
这个感兴趣的读者可以自行去查阅相关资料或者自己推导,可能后面我也会写一些排序的文章(没办法,太重要了)。
6、小测试
#include "list.h" #include <iostream> #include <cstdlib> int main() { std::cout << "-------------- list test -----------------" << std::endl << std::endl; yang::list mylist; for (int i = 0; i < 10; ++i) { if (i % 2 == 0) mylist.push_back(i); else mylist.push_front(i); } auto it = mylist.begin(); std::cout << "elements are : "; for (; it != mylist.end(); ++it) std::cout << *it << std::ends; std::cout << std::endl << std::endl; if (mylist.unsorted()) std::cout << "this is unsorted list !" << std::endl << std::endl; std::cout << "--------- bubble sort ----------" << std::endl << std::endl; mylist.sort(); std::cout << "elements are : "; for (it = mylist.begin(); it != mylist.end(); ++it) std::cout << *it << std::ends; std::cout << std::endl << std::endl; it = ++mylist.begin();//迭代器指向第二个元素 it = mylist.erase(it); //删除第二个元素,value = 1 mylist.pop_front();//删除首个元素,value = 0 mylist.pop_back(); //删除最后一个元素,value = 9 std::cout << "------ size is : " << mylist.size() << std::endl << std::endl; std::cout << "elements are : "; for (auto it1 = mylist.begin(); it1 != mylist.end(); ++it1) std::cout << *it1 << std::ends; std::cout << std::endl << std::endl; *(++it) = 4; // 此时有两个元素值为4 std::cout << "elements are : "; for (it = mylist.begin(); it != mylist.end(); ++it) std::cout << *it << std::ends; std::cout << std::endl << std::endl; mylist.remove(4); std::cout << "after calling remove(4) the elements are : "; for (it = mylist.begin(); it != mylist.end(); ++it) std::cout << *it << std::ends; std::cout << std::endl << std::endl; mylist.clear(); std::cout << "--------- after calling clear() the list size is : " << mylist.size() << std::endl<<std::endl; system("pause"); return 0; }
测试结果如下:
小结:本章主要讲了增删改查中删的相关操作和冒泡排序算法。在这章里,我们主要是通过图来分析思路,在实际过程中,借助画图和纸上计算是非常重要的辅助手段。在下一章里,将会讲到swap,merge,reverse等接口。
参考资料:
STL 源码剖析 侯捷著
数据结构(C++语言版)第三版 邓俊辉著
gcc 2.95 source code
https://zhuanlan.zhihu.com/p/24050357
相关文章推荐
- C/C++版数据结构之链表<三>
- C++ List(#include<list>)
- 浅谈引用<三> C++中指针和引用的区别
- C++--vector<>容器,List<>链表,map<>容器的用法
- [C++] MyList<T>
- 一起学Maven(Maven的依赖管理特性)<三>
- 浅谈STL list<T>链表容器和迭代器的使用C++实现
- C++ Greedy Snake的OOP实现 贪食蛇 <list> STL初次学习
- 从c到c++<三>
- C++写的一个List<T>
- 对从c++中向qml中导入list<qobject*>的操作的深入学习
- listvew<三> 实现item内部控件的点击事件
- c/c++学习之c++ 中的list <>容器
- ACE_TAO sequence<string> strList C++ 映射
- <三> c++之static
- c++入门 (头文件)<三>
- C++ List(#include<list>) 动态数组以及取其中第N个元素的方法
- List<T> C++实现
- C/C++版数据结构之链表<三>
- C++ list<list<int> >类型的对象遍历