C++——数据结构

前言

线性表(有序表)分为数组描述的线性表和链式描述的线性表。
数组和矩阵。
栈和队列。
跳表和散列。
二叉树和其他树。
优先级队列。
竞赛树和搜索树。
平衡搜索树。
图。

一、线性表——数组描述

(1)数组类型(通过模板类解决)和数组长度(动态数组解决)。

(2)动态数组,可以使用一个变量(非const值)从键盘上获取数组的长度:

int n;
printf("请输入数组的长度:"); 
scanf("%d",&n);
int sz[n];//动态数组

(3)没有实现代码的成员函数称为纯虚函数;具体类可以实例化,抽象类可以建立对象指针;一个抽象类的派生类,只有实现了基类的所有纯虚函数才是具体类,否则依然是抽象类而不能实例化。

(4)当一个对象传值给一个函数,或者一个函数返回一个对象时,都需要调用复制构造函数。

(5)迭代器iterator是一个指针,指向对象的一个元素。一个迭代器可以用来逐个访问对象的所有元素。

//输出在范围[start, end)之内的元素 //start指向首元素,end指向要输出的最后一个元素的下一个位置
for(iterator i = start; i != end; i++){
	cout << *i << " ";//*i解引用,取值
}

(6)抽象数据类型linearList

empty();
size();
get(index);//返回线性表中索引为index的元素
erase(index);
insert(index, x);
output();//从左到右输出

二、线性表——链式描述

(1)在链式描述中,线性表的元素在内存中的存储位置是随机的。每个元素都有一个明确的指针或链指向线性表的下一个元素的位置(即地址)。分为数据域和链域

(2)每个节点只有一个链,称为单向链表。

(3)在链表的前面增加一个节点,称为头结点,只要将单向链表的尾节点与头节点连接起来,单向链表就成为循环链表。

(4)双向链表:每个元素节点即有一个指向后继的指针next,又有一个指向前驱的指针previous,其中next指针指向右边节点(如果存在),previous指针指向左边节点(如果存在)。

(5)箱子排序:首先把分数相同的节点放在同一个箱子里,然后把箱子链接起来就得到有序的链表。

(6)如果一个排序方法能够保持同值元素之间的相对次序,则该方法称为稳定排序。

(7)基数排序:不直接对数进行排序,而是把数按照某种基数分解为数字,然后对数字排序。
把数分解为数字需要除法和取模操作,如果用基数r来分解,那么从最低位到最高位的数字分解式是:

x%r; (x%r^2)/r; (x%r^3)/r^2;...

(8)凸包

三、数组和矩阵

(1)二维数组:

int s[u1][u2];
//行映射
map(i1, i2) = i1 * u2 + i2;

三维数组:

int s[u1][u2][u3];
//行映射
map(i1, i2, i3) = i1 * u2 * u3 + i2 * u3 + i3;

一个二维数组是否是规则的取决于每一行的元素个数是否相同。

(2)一个m*n的矩阵,若大多数元素都是0,则称为稀疏矩阵,否则称为稠密矩阵。

(3)把每行的非0元素串接在一起,构成一个链表,称作行链表

四、栈

(1)先进后出。

(2)栈是一种特殊的线性表,插入和删除在同一端进行,称为栈顶,另一端称为栈底。

(3)计算机执行递归函数,是用递归工作栈。当一个函数被调用时,一个返回地址和被调函数的局部变量和形参的值都存放在递归工作栈中。

empty();
size();
top();
pop();
push(x);

五、队列

(1)先进先出。

(2)队列是一种特殊的线性表,插入和删除分别在两端进行,插入端称为队尾,删除端称为队首。

empty();
size();
front();
back();
pop();
push(x);

六、跳表和散列

(1)为了提高有序链表的查找性能,可以在全部或部分节点上增加额外的指针。在查找时,通过这些指针可以跳过链表的若干个节点,不必从左到右连续查看所有节点。增加了额外的向前指针的链表叫做跳表

(2)散列是用来查找、插入、删除的另一种随机方法。

hash_map;
hash_multimap;
hash_multiset;
hash_set;

(3)字典是由一些形如(k,v)的数对所组成的集合,k是关键字,v是与关键字k对应的值。

empty();
size();
find(k);
insert(p);//p.first和p.second分别表示数对p的关键字和值
erase(k);

(4)字典的另一种表示方法是散列。它用一个散列函数(哈希函数)把字典的数对映射到一个散列表(哈希表)的具体位置。

(5)散列表的每一个位置叫一个,桶的数量等于散列表的长度或大小。

(6)当两个不同的关键字所对应的起始桶相同时,就是冲突发生了。
如果存储桶没有空间存储一个新数对,就是溢出了。

(7)当映射到散列表中任何一个桶里的关键字数量大致相等时,冲突和溢出的平均数最少,称为均匀散列函数;表现良好的均匀散列函数被称为良好散列函数

(8)找到下一个可用的桶——解决溢出,线性探查法。
如果散列表的每一个桶可以容纳无限多个记录,那么溢出问题就不存在了,实现这个目标的一个方法是给散列表的每一个位置配置一个线性表。这时每一个数对可以存储在它的起始桶线性表中。

七、二叉树和其他树

(1)一棵树t是一个非空的有限元素的集合,其中一个元素为root),其余的元素(如果有的话)组成t子树
在层次数据中最高层的元素是根,其直接下一级元素是子树的根。
在画一棵树时,每个元素都代表一个节点
在树中没有孩子的元素称为叶子
树根是树中唯一一个没有父母的元素;
树根是1级,其孩子是2级;
一棵树的高度深度是树中级的个数;
一个元素的是指其孩子的个数,叶节点的度为0;
一棵树的度是其元素的度的最大值。

(2)一棵二叉树t是有限个元素的集合(可以为空)。当二叉树非空时。其中有一个元素称为,余下的元素(如果有的话)被划分成两棵二叉树,分别称为t左子树右子树
二叉树的每个元素都恰好有两棵子树(其中一个或两个可能为空),树的每个元素可有任意数量的子树
二叉树中元素的子树是有序的,树中元素的子树是无序的;
二叉树可以为空,树不能为空。

(3)二叉树特性:
n个元素,有n-1条边;
高度为h,最少有h个元素,最多有2^h - 1个元素;
n个元素,高度最大为n,最小高度为log2(n+ 1)

(3)当高度为h的二叉树恰好有2^h - 1个元素时,称其为满二叉树
当高度为h的二叉树,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树
满二叉树是完全二叉树的一个特例。

(4)一个有n个元素的二叉树可能最多需要2^n个空间来存储(包括数组的0位置);
当根节点以外的每个节点都是其父节点的右孩子时,存储空间最大,称为右斜二叉树
如果二叉树的编号不是从1开始,而是从0开始,则最坏情况的空间需求是2^n - 1

(5)每个节点有两个指针域leftright,有一个元素域val

(6)前序遍历(中左右)、中序遍历(左中右)、后序遍历(左右中)、层序遍历(每一层从左到右依次访问树的元素)。
层序遍历需要队列

vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        
        vector<vector<int>> result;
        
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;
            // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                vec.push_back(node->val);
                
                if (node->left) que.push(node->left); //从左至右遍历
                if (node->right) que.push(node->right);
            }
            result.push_back(vec);
        }
        return result;
    }

(7)二叉树:

empty();
size();//节点个数
preOrder(visit);
inOrder(visit);
postOrder(visit);
levelOrder(visit);

八、优先级队列

(1)在优先级队列中,元素出队列的顺序由元素的优先级决定。可按递增顺序,可按递减顺序,但不是元素进入队列的顺序。

(2)堆是一棵完全二叉树,是实现优先级队列效率很高的数据结构。
C++的STL类priority-queue是用堆实现的优先级队列。

empty();//当队列为空返回true
size();
top();//最大优先级队列中返回优先级最大的元素,最小优先级队列中返回优先级最小的元素
pop();//最大优先级队列中删除优先级最大的元素,最小优先级队列中删除优先级最小的元素
push(x);

(3)大根树中每个节点的值都大于或等于其子节点的值;小根树中每个节点的值都小于或等于其子节点的值。

(4)一棵二叉树称为高度优先左高树HBLT),当且仅当其任何一个内部节点的左孩子的s(最短路径)值都大于或等于右孩子的s值。
一棵二叉树称为重量优先左高树WBLT),当且仅当其任何一个内部节点的左孩子的w(节点数目)值都大于或等于右孩子的w值。

(5)一棵二叉树,如果对一组给定的频率,其编码位串长度WEP最小,那么这棵二叉树称为霍夫曼树

九、竞赛树和搜索树

(1)竞赛树(也称选择树)的基本操作是替换最大(或最小)元素。

(2)二叉搜索树是一棵二叉树,可能为空;
非空的二叉搜索树特征
每个元素有一个关键字(并且任意两个元素的关键字都不同,即所有的关键字都是唯一的);
在根节点的左子树中,元素的关键字(如果有的话)都小于根节点的关键字;
在根节点的右子树中,元素的关键字(如果有的话)都大于根节点的关键字;
根节点的左、右子树也都是二叉搜索树。

(3)索引二叉搜索树在每个节点中添加一个leftSize域,这个域的值是该节点左子树的元素个数。

(4)抽象数据类型ADT

//bsTree 二叉树
find(k);//返回关键字为k的数对
insert(p);//插入数对p
erase(k);//删除关键字为k的数对
ascend();//按关键字升序输出所有数对

//IndexedBSTree  索引二叉搜索树
find(k);//返回关键字为k的数对
get(index);//返回关键字为k的数对
insert(p);//插入数对p
erase(k);//删除关键字为k的数对
ascend();//按关键字升序输出所有数对

十、平衡搜索树

(1)一个树结构——B-树,它的度大于2,适合外部存储;两种平衡二叉树结构——AVL和红-黑树,适合内部存储

(2)STL类map和multimap使用的是红黑树结构,以保证查找、插入和删除具有对数级的时间性能。

(3)AVL树和红-黑树都使用“旋转”来保持平衡。AVL树插入操作需要一次旋转,删除操作需要O(logn)次操作;红-黑树的插入和删除都只需要一次旋转。

(4)x节点的平衡因子定义为:x的左子树高度 - x的右子树高度。

(5)红黑树中每一个节点的颜色或者是黑色或者是红色:
根节点和所有外部节点都是黑色;
在根至外部节点路径上,没有连续两个节点是红色;
在所有根至外部节点的路径上,黑色节点的数目都相同;
从内部节点指向外部结点的指针是黑色的;
在根至外部节点路径上,没有两个连续的红色指针;
在所有根至外部节点路径上,黑色指针的数目都相同。

(6)红黑树的一个节点的,是从该节点到一外部节点的路径上黑色指针的数量。

(7)h是红黑树高度,n是节点数,r是根节点的阶,则:

h ≤ 2r;
n ≥ 2^r - 1;
h ≤ 2*log2(n + 1);

十一、图

(1)是一个用线或边连接在一起的顶点或节点的集合。是有限集VE的有序对,即G=(V, E),其中V的元素称为顶点(也称节点或点),E的元素称为(也称弧或线)。每一条边连接两个不同的顶点,用元组(i, j)来表示,其中ij是边所连接的两个顶点。

(2)带方向的边叫有向边,不带方向的边叫无向边

(3)有向边(i, j)关联至顶点j关联于顶点i;顶点i邻接至顶点j,顶点j邻接于顶点i
对于无向图来说,“至”和“于”含义相同。

(4)所有边都是无向边叫无向图;所有边都是有向边叫有向图

(5)一个图不可能包含自连边,即(i, i);自连边也叫做

(6)为每条边赋予一个表示成本的值,称之为。这时的图被称为加权有向图加权无向图。一个网络经常指一个加权有向图或加权无向图。

(7)一条路径,如果除第一个和最后一个顶点外,其余所有顶点均不同,那么该路径称为一条简单路径
当且仅当G中的每一对顶点之间都有一条路径,称G连通的

(8)如果一个图H的顶点和边的集合分别是G的顶点和边的集合的子集,称图H是图G子图
一条始点和终点相同的简单路径称为环路
没有环路的连通无向图是
一个G的子图如果包含了G的所有顶点且是一棵树,则称为G生成树

(9)每条边都有一个顶点在A中,另一个顶点在B中,有这样特征的叫二分图。

(10)无向图中,与一个顶点相关联的边数称为该顶点的
入度是指关联至该顶点的边数。出度是指关联于该顶点的边数。

(11)一个具有n个顶点和n(n - 1)/2条边的无向图是一个完全图

(12)抽象数据类型graph

numberOfVertices();//返回图的顶点数
numberOfEdge(i, j);//返回图的边数
existsEdge(i, j);//如果边(i, j)存在返回true
insertEdge(theEdge);//插入边
eraseEdge(i, j);//删除边
degree(i);//返回顶点i的度,只用于无向图
inDegree(i);//返回顶点i的入度
outDegree(i);//返回顶点i的出度

(13)对无向图最常用的描述方法都是基于邻接的方式:邻接矩阵邻接链表邻接数组

(14)图的遍历:
.广度优先搜索(BFS):从一个顶点开始,搜索所有可到达顶点的方法。可用队列实现。

深度优先搜索(DFS):可用递归实现。

(15)连通图;
广度优先生成树;
深度优先生成树。

你可能感兴趣的:(C++,互联网学习,数据结构,c++,算法,开发语言)