线性结构-链表、栈、队列应用场景
一、单链表数据结构定义
- python版
class ListNode: def __init__(self, val, next_node = None): self.val = val self.next = next_node
2.C++版
struct ListNode { int value; ListNode *next; ListNode(int item, next = nullptr) { value = item; next = next; } };
3.go版
type ListNode struct { val int next *ListNode }
4.js版
class ListNode{ constructor(data) { this.value = data; this.next = null; } }
二、链表的优缺点及应用场景事例
链表优点:适用于对节点的增删改操作,时间复杂度O(1);
链表缺点:相对于顺序表,除保存数据外,还额外增加存放下个节点地址的内存开销;
同时单链表相对于双链表,查询某个节点从头遍历,双链表双向查找可进可退,缺点是需增加节点的前驱地址的内存开销;
为提高查询效率,同时保留增删改的执行效率,因此,引入跳表数据结构
跳表数据结构定义:
// 跳跃表节点定义 struct skipListNode { struct skipListLevel { // 前进指针 skipListNode *forward; // 跨度 unsigned int span; } level[]; // 后退指针 struct skipListNode *backward // 分值 double score; // 成员对象 robj *obj; } skipListNode; // 跳跃表定义 struct skipList { // 表头节点和表尾节点 struct skipListNode *header, *tail; // 表中节点数量 unsigned long length; // 表中节点层数 int level; };
跳表是一种有序的数据结构,通过在每个节点中维护多个指向其他节点的指针,从而达到快速访问节点的目的,跳表平均复杂度O(logN),最坏复杂的度O(N),多数情况下跳表的效率可以与平衡树相媲美,并且跳表比平衡树结构更为简单,应用场景中redis的有序集合底层实现就使用跳表结构;
链表实现LRU缓存淘汰策略事例:
struct ListNode { int value; ListNode *next; ListNode(int item, next = nullptr) { value = item; next = next; } }; ListNode* lruStrategy(ListNode* L, int val, int n) { ListNode* head = new ListNode(0, L); ListNode* p = head->next; int index = count = 0; bool isExist = false; while (p) { count++; if (p->value == val) { index = count; isExist = true; } p = p->next; } if (isExist) { delListNode(head, index); addListNode(head, val); } if (count == n) { delListNode(head, n); } addListNode(head, val); } ListNode* addListNode(ListNode* head, int val) { ListNode* p; p->value = val; p->next = head->next; head->next = p; return head->next; } ListNode* delListNode(ListNode* p, int index) { ListNode* p = head; for (int i = 0; i < index; i++) { p = p->next; } p->next = p->next->next; return head->next; }
栈的特点是先进后出,常见应用场景有括号匹配,数制转换,函数调用,表达式求值,二叉树遍历等
栈的链式数据结构定义:
struct LinkStack { int value; LinkStack* next; } *stack;
以有效括号匹配为例:
#include <iostream> #include <stack> using namespace std; class Solution { public: /** * 判定左右括号是否匹配 * @param left * @param right * @return */ bool check(char left , char right){ if(left == '('){ return right == ')' ? true : false; } if(left == '['){ return right == ']' ? true : false; } if(left == '{'){ return right == '}' ? true : false; } return false; } /** * 核心方法 * @param s * @return */ bool isValid(string s) { stack<char> stk; for (int i = 0 ; i < s.size() ; i++) { //左括号,入栈 if (s[i] == '(' || s[i] == '{' || s[i] == '[') { stk.push(s[i]); } if (s[i] != ')' && s[i] != ']' && s[i] != '}') { continue; } if (!check(stk.top(), s[i])) { return false; } stk.pop(); } //循环完毕后,若栈不空,说明左括号个数大于右括号,不匹配 return stk.empty(); } }; int main() { string s = "{dadfsa[fjsfjks]s23u(4sjhd)fks}"; Solution *p = new Solution(); if (p->isValid(s)) { cout << "match success" << endl; return 0; } cout << "match fail!!" << endl; }
队列的特点先进先出,应用场景如排队买票,广度优先遍历等
队列数据结构的定义:
struct QNode { int data; QNode* next; }; struct LinkQueue { QNode* front; //队头指针 QNode* rear; //队尾指针 };