数据结构顾名思义就是一堆数据的组织方式,以方便后续的存取和操作,且好的算法离不开高效管理数据的方法。
数据结构的三要素:
1. 数据集合。通过数据对象的本体(如数组和结构体)保存数据
2. 操作。对数据集合的操作,如插入、存取、查找、以及修改等
3. 规则。保证数据集合按照一定规矩来操作、管理和存取,如以何种顺序存取数据元素
在此介绍几种线性数据结构:
一、栈(Stack)
说明:用于临时保存数据,且按照后入先出的规则管理数据集合,在许多递归式的数学解题中都可应用栈来实现。
操作:
1. push(x) : 在栈顶部添加元素
2. pop() : 从栈顶取数据
3. isEmpty() : 栈是否为空
4. isFull() : 栈是否已满
用数组实现栈的代码:
1 init() 2 top = 0 3 4 isEmpty() 5 return top == 0 6 7 isFull() 8 return top >= Max -1 9 10 push(x) 11 if isFull() 12 error(overwrite) 13 S[++top] = x 14 15 pop() 16 if isEmpty() 17 error(overread) 18 return S[top--]
二、队列(Queue)
说明:队列是一个等待处理的数据行列,当希望按照数据抵达的先后顺序来处理数据时会用到,其按照先入先出的规则管理数据。在许多消息队列或消息系统中都有所应用,往往作为两个系统或进程间的数据缓冲区,可实现较好的用户体验。
操作:
1. enqueue(x) : 在队列末尾添加元素
2. dequeue() : 从队头中取出元素
3. isEmpty() : 队列是否空
4. isFull() : 队列是否满
队列可区分为线形和环形,但是线形的队列容易导致部分空间被浪费(因每次从队头中取元素使得head加1,若要防止这一情况需让head时常保持在0,即每次执行完dequeue后应让数据整体向数组开头移动,但这将增加复杂度),而环形队列能有效避免该问题。
环形缓冲区由一维数组构成,指示队列范围的head和tail指针在超出数组范围时重新从数组开头开始循环,即如果指针加1之后超出了数组范围,就重新置为0,其代码实现如下:
1 init() 2 head = tail = 0 3 4 isEmpty() 5 return head == tail 6 7 isFull() 8 return head == (tail + 1) % MAX 9 10 enqueue(x) 11 if isFull() 12 error(overwrite) 13 Q[tail] = x 14 if tail + 1 = MAX 15 tail = 0 16 else 17 tail++ 18 19 dequeue() 20 if isEmpty() 21 error(overread) 22 x = Q[head] 23 if head + 1 = MAX 24 head = 0 25 else 26 head++ 27 return x
三、链表(List)
链表主要由结构体来实现,在C++中即由多个节点(node)来构成,每个节点由指针域和数据域组成,能够高效的在链表特定位置进行插入或删除操作,同时避免内存空间浪费(需要多少就申请多少)。此外,链表基本数据结构是实现高等数据结构的基础。
链表有许多不同的形式,如单向链表、双向链表、环形链表以及多个前驱或后驱节点的链表。在此仅介绍双向链表
操作:
1. insert(x) : 在链表中添加含有键值x的节点
2. delete(x) : 删除第一个含有键值x的节点
3. deleteFirst : 删除链表的表头节点
4. deleteLast : 删除链表的表尾节点
代码实现如下:
1 // 节点 2 struct Node { 3 int key; 4 Node *prev, *next; 5 }; 6 7 // 初始化 8 Node *begin; 9 void init() { 10 begin = (Node *) malloc (sizeof(Node)); 11 begin->next = begin; 12 begin->prev = begin; 13 } 14 15 // 插入元素 16 void insert (int key) { 17 Node *x = (Node *)malloc(sizeof(Node)); 18 x->key = key; 19 //在头节点后插入元素 20 x->next = begin->next; 21 begin->next->prev = x; 22 begin->next = x; 23 x->prev = begin; 24 } 25 26 // 搜索元素 27 Node* listSearch(int key) { 28 Node *current = begin->next; 29 while (current != begin && current->key != key) 30 current = current->next; 31 return current; 32 } 33 34 //删除元素 35 void deleteNode(Node* t) { 36 if (t ==begin) return; //头节点不作处理 37 t->prev->next = t->next; 38 t->next->prev = t->prev; 39 free(t); 40 } 41 42 void deleteFirst() { 43 deleteNode(begin->next); 44 } 45 46 void deleteLast() { 47 deleteNode(begin->prev); 48 } 49 50 void deleteKey (int key) { 51 deleteNode(listSearch(key)); 52 }