线性表
顺序表
顺序表是一种简单的线性结构,逻辑上相邻的数据在计算机内的存储位置也是相邻的,可以快速定位第几个元素,中间不允许有空值,插入、删除时需要移动大量元素。
顺序表的三个要素
- 用 elements 记录存储位置的基地址
- 分配一段连续的存储空间size
- 用 length 记录实际的元素个数,即顺序表的长度
顺序表的定义和具体实现
#pragma once
#define SIZE 100
class List {
public:
List(int length = 10);
List(const List& other);
List& operator=(const List& other);
bool push(int e);
bool insert(int index, int e);
bool erase(int index);
~List();
//private:
int* arr;//数组
int length;//当前元素个数
int size;//分配空间大小
};
void printList(const List& l);
#include "List.h"
#include <iostream>
List::List(int length) {
this->length = length;
this->size = 100;
arr = new int[size];
}
List::~List() {
if (arr) {
delete[] arr;
arr =nullptr;
}
}
List::List(const List& other) {
this->size = other.size;
this->length = other.length;
this->arr = new int[size];
for (int i = 0; i != length; ++i) {
this->arr[i] = other.arr[i];
}
}
List& List::operator = (const List & other){
if (this->arr) {
delete[]arr;
}
this->size = other.size;
this->length = other.length;
this->arr = new int[size];
for (int i = 0; i != length; ++i) {
this->arr[i] = other.arr[i];
}
return *this;
}
bool List::push(int e) {
if (length == size)return false;
arr[length] = e;
length++;
return true;
}
bool List::insert(int index, int e) {
if (index<0||index>length||length == size)return false;
if (index == length) {
arr[length] = e;
length++;
return true;
}
for (int i = length-1; i >= index; --i) {
arr[i + 1] = arr[i];
}
arr[index] = e;
length++;
return true;
}
bool List::erase(int index) {
if (index < 0 || index >= length)return false;
if (index == length - 1) {
arr[index] = 0;
length--;
return true;
}
for (int i = index; i != length-1; ++i) {
arr[i] = arr[i + 1];
}
arr[length - 1] = 0;
length--;
return true;
}
void printList(const List&l) {
for (int i = 0; i != l.length; ++i) {
std::cout << l.arr[i] << " ";
}
std::cout << std::endl;
}
链表
链表其实就是线性表的链式存储结构,从物理上来说他不是连续的,但从逻辑上它是顺序的。
单链表
#include <iostream>
#include <string>
using namespace std;
struct Link {
int value;
Link* next;
};
bool initLink(Link* &L);
void push_front(Link* &L, int element);
void push_back(Link* &L, int element);
bool insertLink(Link* &L, int index,int element);
bool eraseIndex(Link* &L, int index);
bool eraseValue(Link* &L, int element);
bool clearLink(Link* &L);//释放链表的空间
int findValue(Link* &L, int element);//查找element值所对应的下标
int findIndex(Link* &L, int index);//查找index下标所对应的值
void printLink(Link* &L);
int main(void) {
Link* L = NULL;//头结点
initLink(L);
if (L==NULL) {
cout << "初始化分配空间失败!" << endl;
exit(-1);
}
int count=0;//插入结点个数
int i = 1;//当前结点计数
int element = 0;
cout << "请输入要插入的结点个数:";
cin >> count;
try {
if (count < 1) {
throw string("插入结点个数太少!");
}
}
catch (string error) {
cout << error << endl;
}
while (count--) {
cout << "请输入第" << i++<<"个数据:";
cin >> element;
push_back(L, element);
}
/*while (count > 0) {
cout << "请输入第" << i << "个数据:";
cin >> element;
push_front(L,element);
--count;
++i;
}*/
/*printLink(L);
cout << "请输入要插入的元素个数:";
cin >> count;
if (count < 1) {
cout << "插入元素过少!" << endl;
}
i = 1;
int index = 0;
while (count--) {
cout << "请输入第" << i++ << "个数据:";
cin >> index >> element;
if (insertLink(L, index, element) == false) {
cout << "随机插入元素失败!" << endl;
}
printLink(L);
}*/
/*eraseIndex(L, 3);
eraseValue(L, 100);
printLink(L);*/
cout << findIndex(L, 1) << endl;
cout << findValue(L, 100) << endl;
printLink(L);
if (clearLink(L) == false) {
cout << "清空链表失败!" << endl;
}
return 0;
}
bool initLink(Link* &L) {
L = new Link;
if (L==NULL) {
return false;
}
L->value = -1;//头结点是不存储数据的
L->next = NULL;//空链表
return true;
}
void push_back(Link* &L, int element) {
Link* p = L;
Link* node = new Link;
node->value = element;
node->next = NULL;//让他成为最后一个结点
while (p->next) {//一直找到尾结点为止
p = p->next;
}
p->next = node;
}
void push_front(Link* &L, int element) {
Link* p = L;
Link* node = new Link;
node->value = element;
node->next = p->next;
p->next = node;
}
void printLink(Link* &L) {
Link* p = L->next;
while (p) {
cout << p->value << " ";
p = p->next;
}
cout << endl;
}
bool insertLink(Link*& L, int index, int element) {
Link* p = L;
Link* node = new Link;
int i = 0;
node->value = element;
while (p && i < index - 1) {
p = p->next;
++i;
}
if (!p || i > index - 1) {//下标不存在或者非法
return false;
}
node->next = p->next;
p->next = node;
return true;
}
bool eraseIndex(Link*& L, int index) {
Link* p = L;
int i = 0;
while (p&& i<index-1) {
p = p->next;
++i;
}
if (p == NULL || i > index - 1) {
return false;
}
Link* q = p->next;
p->next = q->next;
delete q;//析构
return true;
}
bool eraseValue(Link*& L, int element) {
Link* p = L;
Link* q=NULL;
while (p && p->value != element) {
q = p;
p = p->next;
}
if (p == NULL) {
return false;
}
q->next = p->next;
delete p;
return true;
}
bool clearLink(Link*& L) {
Link* p;
p = L;
while (!L) {
return false;
}
while (L) {
L = L->next;
delete p;
p = L;
}
return true;
}
int findValue(Link*& L, int element) {
int i = 1;
Link* p = L->next;
while (p&&p->value!=element) {
p = p->next;
++i;
}
if (p == NULL) {
return -1;
}
return i;
}
int findIndex(Link*& L, int index) {
Link* p = L->next;
int element = 0;
int i = 0;
while (p && i<index) {
element = p->value;
p = p->next;
++i;
}
if (p == NULL||i>index) {
return -1;
}
return element;
}
双链表
双链表在单链表的基础上加入了一个指向上一个结点的指针
#include <iostream>
using namespace std;
struct Link {
int value;
Link* next;
Link* prev;
};
bool initLink(Link*& L);
void push_back(Link*& L, int value);
void push_front(Link*& L, int value);
void printLink(Link*& L);
bool insertLink(Link*& L, int index, int value);
bool eraseIndex(Link*& L, int index);
bool eraseValue(Link*& L, int value);
bool clearLink(Link*& L);
int main(void) {
Link* L;
initLink(L);
for (int i = 0; i != 10; ++i) {
push_back(L, i + 1);
}
for (int i = 0; i != 10; ++i) {
push_front(L, i + 1);
}
insertLink(L, 2, 100);
insertLink(L, 22, 1000);
insertLink(L, 1, 10000);
printLink(L);
eraseIndex(L, 10);
eraseValue(L, 10000);
eraseIndex(L, 1000);
eraseValue(L, 111);
printLink(L);
clearLink(L);
return 0;
}
bool initLink(Link*& L) {
L = new Link;
if (L == NULL) {
return false;
}
L->next = L->prev = NULL;
L->value = -1;
return true;
}
void push_back(Link*& L, int value) {
Link* p = L;
Link* node = new Link;
node->value = value;
node->next = NULL;
while (p->next) {
p = p->next;
}
p->next = node;
node->prev = p;
}
void push_front(Link*& L, int value) {
Link* node = new Link;
node->value = value;
if (L->next == NULL) {
L->next = node;
node->next = NULL;
node->prev = L;
return;
}
node->next = L->next;
L->next->prev = node;
L->next = node;
node->prev = L;
}
void printLink(Link*& L) {
Link* p = L->next;
if (p == NULL) {
return;
}
while (p) {
cout << p->value << " ";
p = p->next;
}
cout << endl;
}
bool insertLink(Link*& L, int index, int value) {
Link* p = L;
Link* node = new Link;
int i = 0;
node->value = value;
while (p&&i<index-1) {
p = p->next;
++i;
}
if (p == NULL||i>index-1) {
return false;
}
node->next = p->next;
node->prev = p;
p->next = node;
if (node->next == NULL) {
return true;
}
node->next->prev = node;
return true;
}
bool eraseIndex(Link*& L, int index) {
Link* p = L;
int i = 0;
while (p && i < index ) {
p = p->next;
++i;
}
if (p == NULL || i > index) {
return false;
}
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
return true;
}
bool eraseValue(Link*& L, int value) {
Link* p = L;
while (p && p->value != value) {
p = p->next;
}
if (p == NULL) {
return false;
}
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
return true;
}
bool clearLink(Link*& L) {
if (L == NULL) {
return false;
}
Link* p = NULL;
while (L) {
p = L->next;
delete L;
L = p;
}
cout << "析构成功!" << endl;
return true;
}
循环链表
循环链表就是将最后一个结点的next指针指向头节点,形成一个闭环
#include <iostream>
#include <string>
using namespace std;
struct Link {
int value;
Link* next;
};
bool initLink(Link*& L);
void push_front(Link*& L, int element);
void push_back(Link*& L, int element);
bool insertLink(Link*& L, int index, int element);
bool eraseIndex(Link*& L, int index);
bool eraseValue(Link*& L, int element);
bool clearLink(Link*& L);//释放链表的空间
int findValue(Link*& L, int element);//查找element值所对应的下标
int findIndex(Link*& L, int index);//查找index下标所对应的值
void printLink(Link*& L);
int main(void) {
Link* L;
initLink(L);
for (int i = 0; i != 10; ++i) {
push_back(L, i + 1);
}
for (int i = 0; i != 10; ++i) {
push_front(L, i + 1);
}
insertLink(L, 2, 100);
insertLink(L, 22, 1000);
insertLink(L, 1, 10000);
printLink(L);
eraseIndex(L, 10);
eraseValue(L, 10000);
eraseIndex(L, 1000);
eraseValue(L, 111);
printLink(L);
clearLink(L);
return 0;
}
bool initLink(Link*& L) {
L = new Link;
if (L == NULL) {
return false;
}
L->value = -1;//头结点是不存储数据的
L->next = L;//空链表
return true;
}
void push_back(Link*& L, int element) {
Link* p = L;
Link* node = new Link;
node->value = element;
node->next = L;//让他成为最后一个结点
while (p->next!=L) {//一直找到尾结点为止
p = p->next;
}
p->next = node;
}
void push_front(Link*& L, int element) {
Link* p = L;
Link* node = new Link;
node->value = element;
/*if (L->next == NULL) {
L->next = node;
node->next = L;
}*/
node->next = p->next;
p->next = node;
}
void printLink(Link*& L) {
Link* p = L->next;
while (p!=L) {
cout << p->value << " ";
p = p->next;
}
cout << endl;
}
bool insertLink(Link*& L, int index, int element) {
Link* p = L->next;
Link* node = new Link;
int i = 0;
node->value = element;
if (p == L) {
L->next = node;
node->next = L;
}
while (p->next!=L && i < index - 1) {
p = p->next;
++i;
}
if (p==L || i > index - 1) {//下标不存在或者非法
return false;
}
node->next = p->next;
p->next = node;
return true;
}
bool eraseIndex(Link*& L, int index) {
Link* p = L->next;
int i = 0;
while (p!=L && i < index - 1) {
p = p->next;
++i;
}
if (p == L || i > index - 1) {
return false;
}
Link* q = p->next;
p->next = q->next;
delete q;//析构
return true;
}
bool eraseValue(Link*& L, int element) {
Link* p = L->next;
Link* q = NULL;
while (p!=L && p->value != element) {
q = p;
p = p->next;
}
if (p==L) {
return false;
}
q->next = p->next;
delete p;
return true;
}
bool clearLink(Link*& L) {
Link* p;
Link* q;
p = L->next;
while (!L) {
return false;
}
if (p == L) {
delete L;
return true;
}
while (p!=L) {
q = p->next;
delete p;
p = q;
}
return true;
}
int findValue(Link*& L, int element) {
int i = 1;
Link* p = L->next;
while (p!=L && p->value != element) {
p = p->next;
++i;
}
if (p == L) {
return -1;
}
return i;
}
int findIndex(Link*& L, int index) {
Link* p = L->next;
int element = 0;
int i = 0;
while (p!=L && i < index) {
element = p->value;
p = p->next;
++i;
}
if (p == L || i > index) {
return -1;
}
return element;
}
队列
队列其实是一种受限的线性表,它在尾部插入元素,在头部删除元素。也有顺序存储和链式存储两种方式,我们可以把队列看成是一种容器,里面分别存储了数据集合的头指针和尾指针。
队列-顺序存储
顺序队列的尾指针是指向最后一个元素的下一个位置,也就是可以插入新元素的下标
#include <iostream>
using namespace std;
#define MAX_SIZE 100
struct queue {
int arr[MAX_SIZE];
int begin;
int end;
};
void initQueue(queue&);
bool push(queue& q, int value);
bool pop(queue& q);
void printQueue(queue& q);
int main(void) {
queue q;
initQueue(q);
for (int i = 0; i != 10; ++i) {
push(q, i + 1);
}
for (int i = 0; i != 5; ++i) {
pop(q);
}
printQueue(q);
return 0;
}
void initQueue(queue& q) {
q.begin = q.end = 0;
}
bool push(queue& q, int value) {
if (q.end == MAX_SIZE) {
return false;
}
q.arr[q.end] = value;
++q.end;
return true;
}
bool pop(queue& q) {
if (q.begin == q.end) {
return false;
}
for (int i = 0; i != q.end-1; ++i) {
q.arr[i] = q.arr[i + 1];
}
--q.end;
return true;
}
void printQueue(queue& q) {
for (int i = 0; i != q.end; ++i) {
cout << q.arr[i] << " ";
}
cout << endl;
}
队列-链式存储
链式队列的尾指针是是真的指向最后一个元素
#include <iostream>
#define MAX_SIZE 10
using namespace std;
struct Node {
int value;
Node* next;
};
struct Queue {
int length;
Node* begin;
Node* end;
};
void initQueue(Queue*& q);
bool isEmpty(Queue*& q);
bool isFull(Queue*& q);
bool push(Queue*& q, int value);
bool pop(Queue*& q);
void printQueue(Queue*& q);
bool clearQueue(Queue*& q);
int main(void) {
Queue* q;
initQueue(q);
for (int i = 0; i != 10; ++i) {
push(q, i + 1);
}
printQueue(q);
for (int i = 0; i != 5; ++i) {
pop(q);
}
printQueue(q);
clearQueue(q);
return 0;
}
void initQueue(Queue*& q) {
q = new Queue;
q->begin = q->end = NULL;
q->length = 0;
}
bool isEmpty(Queue*& q) {
if (q == NULL||q->begin==NULL) {
return true;
}
return false;
}
bool isFull(Queue*& q) {
if (q->length == MAX_SIZE) {
return true;
}
return false;
}
bool push(Queue*& q, int value) {
if (q == NULL || isFull(q)) {
return false;
}
Node* node = new Node;
node->value = value;
node->next = NULL;
if (isEmpty(q)) {
q->begin = q->end = node;
}
else {
q->end->next = node;//插入新结点
q->end = node;//队尾指针指向新的结点
}
++q->length;
return true;
}
bool pop(Queue*& q) {
if (isEmpty(q) || q == NULL) {
return false;
}
Node* p = q->begin;
q->begin = q->begin->next;
delete p;
--q->length;
return true;
}
void printQueue(Queue*& q) {
if (isEmpty(q) || q == NULL) {
return;
}
Node* p = q->begin;
while (p) {
cout << p->value << " ";
p = p->next;
}
cout << endl;
}
bool clearQueue(Queue*& q) {
if (isEmpty(q)) {
delete q;
return true;
}
Node* n = q->begin;
Node* n2 = n;
while (n) {
n = n->next;
delete n2;
n2 = n;
}
delete q;
return true;
}
线程池中的任务队列
线程池由一个任务队列和一组处理任务的线程组成。在我们的程序中,任务其实就是一个具体的函数。我们将一个个这样的函数存储在队列里,就形成了任务队列。任务队列中的任务会由空闲的线程提取并处理
#include <iostream>
#define MAX_SIZE 100
using namespace std;
struct Node {
int id;
void(*fun)();//函数指针
Node* next=NULL;
};
struct Queue {
int length;
Node* front;
Node* back;
};
void initQueue(Queue*& Q);
bool isEmpty(Queue*&);
bool isFull(Queue*&);
bool push(Queue*& Q, Node* N);
bool pop(Queue*& Q);
void printQueue(Queue*&);
void fun1() {
cout << "fun1()" << endl;
}
void fun2() {
cout << "fun2()" << endl;
}
int main(void) {
Node n1, n2;
Queue* Q;
n1.id = 1;
n2.id = 2;
n1.fun = fun1;
n2.fun = fun2;
initQueue(Q);
push(Q, &n1);
push(Q, &n2);
printQueue(Q);
cout << Q->length << endl;
return 0;
}
void initQueue(Queue*& Q) {
Q = new Queue;
Q->length = 0;
Q->back = Q->front = NULL;
}
bool isEmpty(Queue*& Q) {
if (Q->front ==NULL&& Q->back==NULL) {
return true;
}
return false;
}
bool isFull(Queue*& Q) {
if (Q->length == MAX_SIZE) {
return true;
}
return false;
}
bool push(Queue*& Q, Node *N) {
if (isFull(Q)) {
return false;
}
N->next = NULL;
if (isEmpty(Q)) {//空队列
Q->front = Q->back = N;
Q->length++;
return true;
}
Q->back->next = N;
Q->back = N;
Q->length++;
return true;
}
bool pop(Queue*& Q) {
if (isEmpty(Q)) {
return false;
}
Node* n = Q->front;
Q->front = n->next;
if (Q->front == NULL) {//队列为空
Q->back = NULL;
}
Q->length--;
return true;
}
void printQueue(Queue*& Q) {
if (isEmpty(Q)) {
return;
}
Node* n = Q->front;
while (n) {
cout << n->id << endl;
n->fun();
n = n->next;
}
return;
}
循环队列
循环队列就是在删除元素的时候直接将头指针后移,插入元素也不是一直在尾部插入,如果头部有空位的话,会直接在头部插入元素。循环队列有一个位置是不存储元素的,用来判断是否溢出。头指针和尾指针在偏移的时候不能简单的加一了,而是加一然后对数组长度取模,防止下标越界。
#include <iostream>
using namespace std;
#define MAX_SIZE 10
struct queue {
int arr[MAX_SIZE];
int begin;
int end;
};
void initQueue(queue&);
bool isEmpty(queue&);
bool isFull(queue&);
bool push(queue& q, int value);
bool pop(queue& q);
void printQueue(queue& q);
int main(void) {
queue q;
initQueue(q);
for (int i = 0; i != 10; ++i) {
push(q, i + 1);
}
for (int i = 0; i != 10; ++i) {
pop(q);
}
for (int i = 0; i != 100; ++i) {
push(q, (i + 1)*10);
}
printQueue(q);
return 0;
}
void initQueue(queue& q) {
q.begin = q.end = 0;
}
bool isEmpty(queue& q) {
if (q.begin == q.end) {
return true;
}
return false;
}
bool isFull(queue& q) {
//循环队列有一个位置是不存储元素的
//队MAX_SIZE取模是因为end在front后面的时候不会越界
if ((q.end + 1) % MAX_SIZE == q.begin) {
return true;
}
return false;
}
bool push(queue& q, int value) {
if (isFull(q)) {
return false;
}
q.arr[q.end] = value;
q.end = (q.end + 1) % MAX_SIZE;//小心越界,如果到达数组尾部可以直接在头部插入数据
return true;
}
bool pop(queue& q) {
if (isEmpty(q)) {
return false;
}
q.begin = (q.begin + 1) % MAX_SIZE;//小心越界
return true;
}
void printQueue(queue& q) {
for (int i = q.begin; i != q.end; i=(i+1)%MAX_SIZE) {
cout << q.arr[i] << " ";
}
cout << endl;
}
优先队列
优先队列的入队顺序和普通队列没有任何的区别,但是在出队的时候是按照优先级出队的,优先级最高的先出队
#include <iostream>
#define MAX_SIZE 10
using namespace std;
struct Node {
int value;
Node* next;
int priority;//优先级
};
struct Queue {
int length;
Node* front;
Node* back;
};
void initQueue(Queue*& Q);
bool isEmpty(Queue*& Q);
bool isFull(Queue*& Q);
bool push(Queue*& Q, int value, int priority);
bool pop(Queue*& Q);
void printQueue(Queue*& Q);
int main(void) {
Queue* Q;
initQueue(Q);
for (int i = 0; i != 100; ++i) {
push(Q, (i + 1) * 10, i + 1);
}
for (int i = 0; i != 11; ++i) {
pop(Q);
}
return 0;
}
void initQueue(Queue*& Q) {
Q = new Queue;
Q->length = 0;
Q->back = Q->front = NULL;
}
bool isEmpty(Queue*& Q) {
if (Q->front == NULL) {
return true;
}
return false;
}
bool isFull(Queue*& Q) {
if (Q->length == MAX_SIZE) {
return true;
}
return false;
}
bool push(Queue*& Q, int value, int priority) {
if (isFull(Q)) {
return false;
}
Node* N = new Node;
N->next = NULL;
N->value = value;
N->priority = priority;
if (isEmpty(Q)) {
Q->front = Q->back = N;
++Q->length;
return true;
}
Q->back->next = N;
Q->back = N;
++Q->length;
return true;
}
bool pop(Queue*& Q) {
if (isEmpty(Q)) {
return false;
}
Node**prev = &Q->front;//指向被删除结点的前一个结点的next指针,假设第一个优先级就是最高的
Node* prev_node = Q->front;
Node* p, * q;
p = q = NULL;
p = Q->front;//指向第一个结点
q = p->next;//指向第二个结点
while (q) {
if ((*prev)->priority < q->priority) {
prev = &p->next;//指向出队元素的前一个元素的next指针,这样就可以改变next了
prev_node = p;//指向出队元素的前一个元素
}
p = q;
q = q->next;
}
Node* tmp = (*prev);//指向出队的结点;
*prev = tmp->next;//直接更改next,令它指向下一个元素
//prev_node->next = tmp->next;//不能这样使用,这样在删除最后一个元素的时候会出问题
cout << "元素:" << tmp->value << '\t' << "优先级:" << tmp->priority << endl;
delete tmp;
if (Q->length == 0) {//删除的是首元素
Q->back = NULL;
}
//if (*prev == NULL) {//删除的是尾元素
// Q->back =prev_node;//指向前一个元素
//}
if (prev_node->next == NULL) {
Q->back = prev_node;
}
--Q->length;
return true;
}
void printQueue(Queue*& Q) {
if (isEmpty(Q)) {
return;
}
Node* p = Q->front;
while (p) {
cout << "元素:" << p->value << '\t' << "优先级:" << p->priority << endl;
p = p->next;
}
return;
}