第三章 表栈和队列

这章学习最简单的数据结构,表,栈和队列
什么是表
表就是一个序列A1,A2,A3......An
除An外,每个元素都有直接后继
除A1外,每个元素都有直接前驱

表的实现
1. 使用数组
Element array[N];
2. 使用链表
链表分为,单链表,双链表,循环链表
链表在实现的时候需要一个表头以此来消除许多特殊情况
linux内核使用的是:带头的双向循环链表,list_head, 还有专门用于hash的hlist
简单,通用,高效,我一般就用这两个链表,很多公司也是直接用的这两个链表
书中采用的是:带头的单项链表
find(Llist, Element): curr = List->next; while (curr != NULL && curr != Element) curr = curr->next; return curr;
insert(List, Pos, Element): Element->next = Pos->next; Pos->next = Element;
delete(List, Elm): prev = findPrevious(L, E); if (prev->next) prev->next = prev->next->next;
FindPrevious(List, Elm); prev = List; while (prev->next && prev->next->Elm != Elm) prev = prev->next; return prev;

表的例子:
1. Polynomial
2. 基数排序:从低位到高位依次进行桶排序
3.多重链表
说一下 多重链表,就是存在两个对象,这两个对象的关系是多对多
如:书上的选课,student 和 course这样需要一个结构,连接student和course,暂取名stucur
struct stucur {
struct list_head student_entries; //学生链表
struct list_head course_entries; //课程链表
struct list_head *student; //指向所属的student
struct list_head *course;//指向所属的course
};

struct student{
struct list_head course;
}

struct course {
struct list_head student;
}

栈:
栈就是对表的尾部进行操作,俗称先进后出FILO

栈的实现
1. 数组
2. 链表:每次只需要在表头部或者尾部进行操作即可

栈的应用:
1. 括号的平衡(([[]]))
2. 中缀表达式转为后缀表达式,求值
3. 将函数递归转为循环,或者使用栈

队列:
队列就是排队,先进先出,FIFO

队列的实现:
1. 数组
2. 链表:在链表尾部加入数据,在头部删除数据即可

线性结构主要是这三种:表,队列,栈

还有一种线性结构用得也挺多的。尾队列


线性结构都很简单
关键是写出通用且简单的线性结构
下面介绍四种将数据做成通用型的方法(就行C++的模板一样)
1. 使用Linux内核的方式。将结构嵌入到特定的结构中
特点:实现的时候不需要指定类型,使用的时候再指出类型,和member
container_of, offsetof用得真心牛逼
参考:linux list.h

2. 使用宏来实现
特点:定义的时候直接将类型传递
参考:Radvision的List Map, List

TAILQ使用了这两种的结合。
需要嵌入到别的结构体,也需要利用宏定义指定具体的类型
tailq源码:
#define TAILQ_ENTRY(type)
struct {
    struct type * tqe_next;
    struct type **tqe_prev;
}
#define TAILQ_HEAD(name, type)
struct name{
    struct type * tqh_head;
    struct type **tqh_last;
}
其实可以改成这种风格
strcut tailq_entry {
    struct tailq_entry *tqe_next, **tqe_prev;
}
struct tailq_head {
    struct tailq_entry *tqh_first;
    struct tailq_entry **tqh_tail;
}
妈的。瞬间就成了 hlist了,除了在head多了一个tqh_tail;
如果变成这样,那还不如直接用list_head. 总的性能消耗一样
那还是别变了,保持原样吧。

3. 使用变长结构体
struct S {
    int xxx;
    int len;
    char data[0];
}
参考:redis的skiplist, Radvision的AVL树

4. 使用void *的结构体
struct S {
    int xxx;
    void *data;
}
参考:Radvion的图
之前的图论算法完全不行
后面看到了这种图的实现,表示学到了
Graph, 包含GraphNode List, 包含GraphLink List in,out;
和普通的邻接链表相比,将边分成了,入边和出边

只要你能写出简单的,好用的,通用的接口,最底层怎样表示其实不太重要,个人习惯吧

像这些优秀代码以后建议都存起来吧
https://github.com/JonlyLinux/Library

你可能感兴趣的:(数据结构与算法分析读书笔记,数据结构)