数据结构知识点总结
一、排序
1.快速排序:2个以下数据直接返回.否则选最左边值为参考,将序列分2部分,一边大于参考值,一边小于参考值。对两边递归排序。
2.归并排序:分解待排序序列到1个/组,再依次合并回原序列。
3.堆排序:把所有数据建成一个堆,最大值在堆顶,然后将堆顶数据和最后一个数据交换。不断依次重建堆、交换数据。
4.Shell排序:将数据分成不同组,先对每一组进行排序,然后再对所有的元素进行一次插入排序,以减少数据交换和移动的次数。
5.插入排序:通过把序列中的值插入一个已经排序好的序列中,直到该序列的结束。
6.冒泡排序:通过一趟又一趟地比较数组中的每一个元素,使较大的数据下沉,较小的数据上升。
7.基数排序
算法编号 | 平均时间 | 是否稳定 | 空间复杂度 | 备注 |
1 | O(nlogn) | 否 | O(nlogn) | 适用于n大 |
2 | O(nlogn) | 是 | O(1) | 适用于n大 |
3 | O(nlogn) | 否 | O(1) | 适用于n大 |
4 | O(nlogn) | 否 | O(1) | 分组是否合理影响很大 |
5 | O(n2) | 是 | O(1) | 适用于大部分有序 |
6 | O(n2) | 是 | O(1) | 适用于n小 |
7 | O(logRB) | 是 | O(n) | B是真数,R是基数 |
二、查找
1.顺序查找:逐个比较
2.折半查找:二分查找(应用于已按一定顺序排好的数据)
3.哈希查找:在记录的存储位置和记录的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。查找时,根据这个确定的对应关系找到给定值的映射f(key),若查找集合中存在这个记录,则必定在f(key)的位置上。
哈希函数的构造方法:直接定址法、数字分析法、平方取中法、折叠法、除留余数法、随机数法
4.二叉树查找
5.索引查找
查找算法 | 时间复杂度 | 空间复杂度 |
顺序查找 | O(n) | O(n) |
折半查找 | Log2(n) |
|
二叉树查找 | O(lgn) |
三、链表和数组
1.链表和数组的区别:
(1)内存方面:数组静态分配内存,链表动态分配内存;数组在内存中连续,链表不连续;
(2)查找方面:数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n);
(3)处理数据方面:数组需要移动操作数所在位置后的所有数据,插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1)。
(4)值:数组赋值后可以修改元素值,但链表不可以。
四、栈和队列
1.栈和队列的区别:
(1)队列先进先出,栈先进后出。
(2) 对插入和删除操作的"限定"。栈是限定只能在表的一端进行插入和删除操作的线性表。队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
(3)遍历数据速度不同。队列基于地址指针进行遍历,可从头部或尾部开始,其遍历速度比栈快。而栈遍历的时候还得为数据开辟临时空间,保持数据在遍历前的一致性。
2.常考面试题参见:
http://blog.csdn.net/poison_biti/article/details/51671022
http://blog.csdn.net/poison_biti/article/details/51671813
http://blog.csdn.net/poison_biti/article/details/51674185
五、树
树的各种遍历算法
1.先序遍历非递归算法
#define maxsize 100
typedef struct
{
Bitree Elem[maxsize];
int top;
}SqStack;
void PreOrderUnrec(Bitree t)
{
SqStack s;
StackInit(s);
p=t;
while (p!=null || !StackEmpty(s))
{
while (p!=null) //遍历左子树
{
visite(p->data);
push(s,p);
p=p->lchild;
}//endwhile
if (!StackEmpty(s)) //通过下一次循环中的内嵌while实现右子树遍历
{
p=pop(s);
p=p->rchild;
}//endif
}//endwhile
}//PreOrderUnrec
2.中序遍历非递归算法
#define maxsize 100
typedef struct
{
Bitree Elem[maxsize];
int top;
}SqStack;
void InOrderUnrec(Bitree t)
{
SqStack s;
StackInit(s);
p=t;
while (p!=null || !StackEmpty(s))
{
while (p!=null) //遍历左子树
{
push(s,p);
p=p->lchild;
}//endwhile
if (!StackEmpty(s))
{
p=pop(s);
visite(p->data); //访问根结点
p=p->rchild; //通过下一次循环实现右子树遍历
}//endif
}//endwhile
}//InOrderUnrec
3.后序遍历非递归算法
#define maxsize 100
typedef enum{L,R} tagtype;
typedef struct
{
Bitree ptr;
tagtype tag;
}stacknode;
typedef struct
{
stacknode Elem[maxsize];
int top;
}SqStack;
//后序遍历
void PostOrderUnrec(Bitree t)
{
SqStack s;
stacknode x;
StackInit(s);
p=t;
do
{
while (p!=null) //遍历左子树
{
x.ptr = p;
x.tag = L; //标记为左子树
push(s,x);
p=p->lchild;
}
while (!StackEmpty(s) &&s.Elem[s.top].tag==R)
{
x = pop(s);
p = x.ptr;
visite(p->data); //tag为R,表示右子树访问完毕,故访问根结点
}
if (!StackEmpty(s))
{
s.Elem[s.top].tag =R; //遍历右子树
p=s.Elem[s.top].ptr->rchild;
}
}while (!StackEmpty(s));
}//PostOrderUnrec
4.层次遍历算法
// 二叉树的数据结构
structBinaryTree
{
int value; // 不写模板了,暂时用整形代替节点的数据类型
BinaryTree *left;
BinaryTree *right;
};
BinaryTree*root; // 已知二叉树的根节点
//层次遍历
voidLevel( const BinaryTree *root )
{
Queue *buf = new Queue(); // 定义一个空队列,假设此队列的节点数据类型也是整形的
BinaryTree t; // 一个临时变量
buf.push_back(root); //令根节点入队
while( buf.empty == false ) // 当队列不为空
{
p = buf.front(); // 取出队列的第一个元素
cout<<p->value<<' ';
if( p->left != NULL ) // 若左子树不空,则令其入队
{
q.push( p->left );
}
if( p->right != NULL ) // 若右子树不空,则令其入队
{
q.push( p->right );
}
buf.pop(); // 遍历过的节点出队
}
cout<<endl;
}