六、线性表
1. 概念
- 线性表(liner list):也称有序表(ordered list),它的每个实例都是元素的一个有序集合,数据元素之间具有一种线性的或“一对一”的逻辑关系。
- 线性结构(liner structure):将具有线性或“一对一”关系的数据“线性”地存储到物理空间中,这种存储结构就称为线性存储结构。
2. 线性表的特点
- 除第一个元素外,其他每个元素有且仅有一个直接前驱;
- 除最后一个元素外,其他每个元素有且仅有一个直接后继。
3. 线性表的顺序存储
- 概念:顺序表就是顺序存储的线性表,即典型的数组。顺序存储是用一组地址连续的存储单元依次存放线性表中各个元素的存储结构。
- 特点:
- 逻辑上相邻的数据元素,在物理存储上也是相邻的;
- 便于随机访问,查找时间复杂度O(1);
- 存储密度高,但要预先分配“足够”的空间,可能造成存储空间浪费;
- 不便于插入和删除,插入和删除操作会引起大量数据元素的移动;
(ps:存储密度:指一个结点中数据元素所占的存储单元数和整个结点所占的存储单元之比,顺序表的存储密度为1,链式存储密度小于1)
5. 线性表的链式存储
- 概念:用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。在链式结构中,结点包括两个信息:数据和指针。节点除了存储数据元素信息外,还要存储它的后继元素的存储地址。
- 特点
- 不用事先分配存储空间的大小,但存储密度较低;
- 没有空间限制,存储元素的个数无上限,基本只与内存空间大小有关;
- 占用额外的空间以存储指针;
- 解决数组无法存储多种数据类型的问题;
- 插入和删除速度快,保留原有的物理顺序,只需要改变指针指向;
- 查找速度慢,需要循环链表访问,需要从头节点开始查找元素; - 单链表
(1)linkList.h
#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
struct Info {
int number;
string name;
};
struct Node {
Info data;
struct Node *next;
Node(Info info):data(info), next(NULL){}
};
class LinkList{
public:
//构造函数
LinkList();
//析构函数
~LinkList();
//在头部插入
void InsertHead(Info data);
//在尾部插入
void InsertTail(Info data);
//插入
void Insert(Info data, int pos);
//删除
void Remove(Info data);
//查找
int Find(Info data);
//倒序
void Reverse();
//链表长度
int Length();
//打印
void Print();
private:
Node *head;
int length;
};
(2)linkList.cpp
#include"linklist.h"
using namespace std;
LinkList::LinkList() {
head = NULL;
length = 0;
}
LinkList::~LinkList() {
Node *temp;
for (int i = 0; i < length; i++) {
temp = head;
head = head->next;
delete temp;
}
}
void LinkList::InsertHead(Info data) {
Insert(data, 0);
}
void LinkList::InsertTail(Info data) {
Insert(data, length);
}
void LinkList::Insert(Info data, int pos) {
if (pos < 0) {
cout << "Pos must greater than 0." << endl;
return;
}
Node *node = new Node(data);
Node *temp = head;
if (pos == 0) {
node->next = temp;
head = node;
length++;
return;
}
if (pos == length) {
while (temp->next) {
temp = temp->next;
}
temp->next = node;
length++;
return;
}
int index = 1;
while (temp != NULL && index < pos) {
temp = temp->next;
index++;
}
if (temp == NULL) {
cout << "Insert failed." << endl;
return;
}
node->next = temp->next;
temp->next = node;
length++;
}
void LinkList::Remove(Info data) {
int pos = Find(data);
if (pos == -1) {
cout << "No such data." << endl;
return;
}
if (pos == 0) {
Node *p = head;
head = head->next;
length--;
delete p;
return;
}
int index = 1;
Node *temp = head;
while (index < pos) {
temp = temp->next;
index++;
}
Node *p = temp->next;
temp->next = temp->next->next;
delete p;
length--;
}
int LinkList::Find(Info data) {
int index = 0;
Node *temp = head;
while (temp != NULL) {
if ((temp->data.name == data.name) && (temp->data.number == data.number)) {
return index;
}
temp = temp->next;
index++;
}
return -1;
}
void LinkList::Reverse() {
if (head == NULL) return;
Node *curNode = head;
Node *nextNode = curNode->next;
Node *temp;
while (nextNode != NULL) {
temp = nextNode->next;
nextNode->next = curNode;
curNode = nextNode;
nextNode = temp;
}
head->next = NULL;
head = curNode;
}
int LinkList::Length() {
return length;
}
void LinkList::Print() {
if (head == NULL) {
cout << "Empty list." << endl;
return;
}
Node *temp = head;
while (temp != NULL) {
cout << temp->data.number << "," << temp->data.name << endl;
temp = temp->next;
}
}
(3)main.cpp
#include"linklist.h"
using namespace std;
int main() {
LinkList head;
Info info0, info1, info2, info3;
info0.number = 000; info0.name = "aaa";
info1.number = 001; info1.name = "bbb";
info2.number = 002; info2.name = "ccc";
info3.number = 003; info3.name = "ddd";
//InsertHead(), Insert(), Print()
head.InsertHead(info0);
head.InsertTail(info1);
head.InsertTail(info3);
head.Insert(info2, 2);
cout << "Insert info0 to info3." << endl;
head.Print();
cout << endl << endl;
//Reverse()
head.Reverse();
cout << "Reverse List." << endl;
head.Print();
cout << endl << endl;
//Find(), Remove, Print()
head.Remove(info0);
head.Remove(info2);
cout << "Remove info0, info2." << endl;
head.Print();
cout << endl << endl;
//Length
int len = head.Length();
cout << "Length is " << len << "." << endl;
system("pause");
return 0;
}
- 双链表的实现
(1)doubleLinkList.h
#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
class doubleLinkList {
public:
struct Node {
int data;
struct Node *next;
struct Node *pre;
Node(int data):data(data), next(NULL), pre(NULL){}
};
doubleLinkList();
~doubleLinkList();
void InsertHead(int data);
void InsertTail(int data);
void Insert(int data, int pos);
void Remove(int data);
int Find(int data);
void Reverse();
void Print();
int Length();
private:
Node *head;
int length;
};
(2)doubleLinkList.cpp
#include "doubleLinkList.h"
using namespace std;
doubleLinkList::doubleLinkList() {
head = NULL;
//head->next = head->pre = NULL;
length = 0;
}
doubleLinkList::~doubleLinkList() {
Node *temp;
for (int i = 0; i < length; i++) {
temp = head;
head = head->next;
delete temp;
}
}
void doubleLinkList::InsertHead(int data) {
Insert(data, 0);
}
void doubleLinkList::InsertTail(int data) {
Insert(data, length);
}
void doubleLinkList::Insert(int data, int pos) {
if (pos < 0) {
cout << "Pos Must Greater Than 0." << endl;
return;
}
Node *node = new Node(data);
Node *temp = head;
if (pos == 0) {
node->next = temp;
if(temp != NULL)
temp->pre = node;
head = node;
length++;
return;
}
if (pos == length) {
while (temp->next) {
temp = temp->next;
}
temp->next = node;
node->pre = temp;
node->next = NULL;
length++;
return;
}
int index = 1;
while (index < pos) {
temp = temp->next;
index++;
}
if (temp == NULL) {
cout << "Insert Failed." << endl;
return;
}
node->next = temp->next;
if (temp->next != NULL)
temp->next->pre = node;
temp->next = node;
node->pre = temp;
length++;
}
int doubleLinkList::Find(int data) {
int pos = 0;
Node *temp = head;
for (int i = 0; i < length; i++) {
if (temp->data == data) {
return pos;
}
temp = temp->next;
pos++;
}
return -1;
}
void doubleLinkList::Remove(int data) {
int pos = Find(data);
if (pos == -1) {
cout << "No such data." << endl;
}
if (pos == 0) {
Node *temp = head;
head = head->next;
delete temp;
length--;
return;
}
int index = 1;
Node *temp = head;
while (index < pos) {
temp = temp->next;
index++;
}
Node *p = temp->next;
temp->next = temp->next->next;
if (temp->next != NULL) {
temp->next->pre = temp;
}
delete p;
length--;
}
void doubleLinkList::Reverse() {
if (head == NULL) return;
Node *curNode = head;
Node *nextNode = curNode->next;
Node *temp;
while (nextNode != NULL) {
temp = nextNode->next;
nextNode->next = curNode;
curNode->pre = nextNode;
if(temp != NULL)
temp->pre = curNode;
curNode = nextNode;
nextNode = temp;
}
head->next = NULL;
head = curNode;
}
void doubleLinkList::Print() {
if (head == NULL) {
cout << "Empty list." << endl;
return;
}
Node *temp = head;
while (temp != NULL) {
cout << temp->data << endl;
temp = temp->next;
}
}
int doubleLinkList::Length() {
return length;
}
(3)main.cpp
#include"doubleLinkList.h"
using namespace std;
int main() {
int data[5] = { 0, 1, 2, 3, 4 };
doubleLinkList head;
//InsertHead(), InsertTail(), Insert(), Print()
head.InsertHead(data[0]);
head.InsertTail(data[1]);
head.InsertTail(data[2]);
head.Insert(data[3], 3);
cout << "Insert data[0] to data[3]." << endl;
head.Print();
cout << endl << endl;
//Reverse()
head.Reverse();
cout << "Reverse List." << endl;
head.Print();
cout << endl << endl;
//Find(), Remove, Print()
head.Remove(data[0]);
head.Remove(data[2]);
cout << "Remove data[0], data[2]." << endl;
head.Print();
cout << endl << endl;
//Insert(),Print()
head.InsertHead(data[0]);
head.Insert(data[4], 3);
cout << "Insert data[0], data[4]." << endl;
head.Print();
cout << endl << endl;
//Length
int len = head.Length();
cout << "Length is " << len << "." << endl;
system("pause");
return 0;
}
七、队列
1. 概念
队列(Queue)是只允许在一端进行插入操作,另一端进行删除操作的线性表。允许插入的端是队尾,允许删除的端是队头。
2. 顺序队列
- 基于数组的存储表示的队列。其数据成员包括,一维数组elements用来存储数据,指针front和rear用来指示队尾队头的位置,maxSize是数组的最大长度。
- 实现
(1)linerQueue.h
#include<iostream>
using namespace std;
template <class T>
class LinerQueue {
public:
LinerQueue(int len);
~LinerQueue();
bool isEmpty();
int Length();
void Rear();
void Front();
void Push(T item);
void Pop();
private:
T *queue;
int front;
int rear;
int length;
};
(2)linerQueue.cpp
#include"linerQueue.h"
using namespace std;
template <class T>
LinerQueue<T>::LinerQueue(int len) {
if (len < 1) {
cout << "Lenfth must > 0." << endl;
return;
}
queue = new T[len];
length = len;
front = rear = 0;
}
template <class T>
LinerQueue<T>::~LinerQueue() {}
template <class T>
bool LinerQueue<T>::isEmpty() {
return rear == front;
}
template <class T>
int LinerQueue<T>::Length() {
return length;
}
template <class T>
void LinerQueue<T>::Front() {
if (isEmpty()) {
cout << "Queue is empty." << endl;
return;
}
cout << "Front element is : " << queue[(front + 1) % length] << endl;
}
template <class T>
void LinerQueue<T>::Rear() {
if (isEmpty()) {
cout << "Queue is empty." << endl;
return;
}
cout << "Rear element is : " << queue[rear] << endl;
}
template <class T>
void LinerQueue<T>::Push(T item) {
if ((rear + 1) % length == front) {
cout << "Queue is full." << endl;
return;
}
rear = (rear + 1) % length;
queue[rear] = item;
}
template <class T>
void LinerQueue<T>::Pop() {
if (isEmpty()) {
cout << "Queue is empty." << endl;
return;
}
front = (front + 1) % length;
}
(3)main.cpp
#include"linerQueue.h"
#include"linerQueue.cpp"
using namespace std;
int main() {
LinerQueue<int> que(10);
for (int i = 0; i < 4; i++) {
que.Push(i);
}
cout << "---------- Push elements 0, 1, 2, 3. ----------" << endl;
que.Front();
que.Rear();
que.Pop();
que.Pop();
que.Pop();
que.Pop();
cout << "---------- Pop emements 0, 1, 2, 3. ----------" << endl;
que.Front();
que.Rear();
que.Push(10);
cout << "---------- Push element 10. ----------" << endl;
que.Front();
que.Rear();
system("pause");
return 0;
}
3. 链式队列
八、堆、栈
九、树
十、二叉树
1. 概念
-
二叉树是每个结点最多有两个子树的树结构。
-
特点:
(1)有唯一的根节点;
(2)每一个左子树或右子树同时也是二叉树。 -
完全二叉树
设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布。 -
满二叉树
深度为k,且有2^k-1个结点的二叉树,称为满二叉树。这种树的特点是每一层上的结点数都是最大结点数。满二叉树是完全二叉树的特例。
2. 实现
3. 遍历
- 前序遍历
(1)递归实现
void preOrderTraverse1(TreeNode root) {
if (root != NULL) {
cout << root.val << " " ;
preOrderTraverse1(root.left);
preOrderTraverse1(root.right);
}
}
(2)非递归实现
void preOrderTraverse2(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode pNode = root;
while (pNode != NULL || !stack.isEmpty()) {
if (pNode != NULL) {
cout << pNode.val << " " ;
stack.push(pNode);
pNode = pNode.left;
} else { //pNode == null && !stack.isEmpty()
TreeNode node = stack.pop();
pNode = node.right;
}
}
}
- 中序遍历
(1)递归实现
public void inOrderTraverse1(TreeNode root) {
if (root != NULL) {
inOrderTraverse1(root.left);
cout << root.val << " " ;
inOrderTraverse1(root.right);
}
}
(2)非递归实现
- 后序遍历
(1)递归实现
void postOrderTraverse1(TreeNode root) {
if (root != NULL) {
postOrderTraverse1(root.left);
postOrderTraverse1(root.right);
cout << root.val << " " ;
}
}
(2)非递归实现
- 层次遍历
(1)递归实现
(2)非递归实现