1. 顺序表的原理以及实现:
1.1 什么是顺序表:
顺序表是在计算机内存中以数组的形式保存的线性表,顺序表是简单的一种线性结构,逻辑上相邻的数据在计算机内的存储位置也是相邻的,可以快速定位第几个元素,中间不允许有空值,插入、删除时需要移动大量元素。
1.2 什么是线性表:
线性表是从逻辑结构的角度来说的,除了头和尾之外,它的每一个元素都只有一个前驱元素和一个后驱元素。各种队列(单向、双向、循环队列),栈等都是线性表的不同例子。而本文题目的 顺序表 也是线性表的一种。
1.3 顺序表与链表的区别:
首先,顺序表与链表均属于线性表,只是在逻辑结构和存储方式上有所不同。
顺序表:线性表采用顺序存储的方式存储就称之为顺序表,顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。
链表: 线性表采用指针链接的方式存储就称之为链表。
1.4 线性表与数组的区别:
线性表是从逻辑结构的角度来说的,而数组是从物理存贮的角度来说的,线性表可以用数组存贮也可以用链表来存贮。同样的队列和栈也可以用数组和链表存贮,各有利弊。根据具体情况灵活选择。
在C语言中,数组长度不可变,线性表长度是动态可变的。
1.5 顺序表的三个要素:
- 用elems 记录存储位置的基地址
- 分配一段连续的存储空间size
- 用length 记录实际的元素个数,即顺序表的长度
结构体定义
#define MAX_SIZE 100 struct _SqList { ElemType *elems; // 顺序表的基地址 int length; // 顺序表的长度 int size; // 顺序表总的空间大小 }
顺序表的初始化
1 #define MAX_SIZE 100 2 typedef struct 3 { 4 int* elems; // 顺序表的基地址 5 int length; // 顺序表的长度 6 int size; // 顺序表的空间 7 }SqList; 8 9 bool initList(SqList& L) //构造一个空的顺序表L 10 { 11 L.elems = new int[MAX_SIZE]; //为顺序表分配Maxsize 个空间 12 if (!L.elems) return false; //存储分配失败 13 L.length = 0; //空表长度为0 14 L.size = MAX_SIZE; 15 return true; 16 }
2. 顺序表添加元素:
1 bool listAppend(SqList &L, int e) 2 { 3 if(L.length==MAX_SIZE) return false; //存储空间已满 4 L.elems[L.length] = e; 5 L.length++; //表长增1 6 return true; 7 }
3. 顺序表插入元素
1 bool listInsert(SqList& L, int i, int e) 2 { 3 if (i < 0 || i >= L.length)return false; //i 值不合法 4 if (L.length == MAX_SIZE) return false; //存储空间已满 5 6 for (int j = L.length - 1; j >= i; j--) 7 { 8 L.elems[j + 1] = L.elems[j]; //从最后一个元素开始后移,直到第i 个元 素后移 9 } 10 11 L.elems[i] = e; //将新元素e 放入第i 个位置 12 L.length++; //表长增1 13 14 return true; 15 }
4. 顺序表删除元素
1 bool listDelete(SqList& L, int i) 2 { 3 if (i < 0 || i >= L.length) return false; //不合法 4 if (i == L.length - 1) //删除最后一个元素,直接删除 5 { 6 L.length--; 7 return true; 8 } 9 for (int j = i; j < L.length - 1; j++) 10 { 11 L.elems[j] = L.elems[j + 1]; //被删除元素之后的元素前移 12 } 13 L.length--; 14 15 return true; 16 }
5. 顺序表销毁
1 void destroyList(SqList& L) 2 { 3 if (L.elems) delete[]L.elems; //释放存储空间 4 L.length = 0; 5 L.size = 0; 6 }
6. 完整实现
1 #include <iostream> 2 3 using namespace std; 4 #define MAX_SIZE 100 5 6 typedef struct 7 { 8 int* elems; // 顺序表的基地址 9 int length; // 顺序表的长度 10 int size; // 顺序表的空间 11 }SqList; 12 13 bool initList(SqList& L) //构造一个空的顺序表L 14 { 15 L.elems = new int[MAX_SIZE]; //为顺序表分配Maxsize 个空间 16 if (!L.elems) return false; //存储分配失败 17 L.length = 0; //空表长度为0 18 L.size = MAX_SIZE; 19 return true; 20 } 21 22 /* 23 bool getElem(SqList &L,int i,int &e) 24 { 25 //防御性检查 26 if (i<1||i>L.length) return false; 27 e=L.elems[i-1]; //第i-1 的单元存储着第i 个数据 28 return true; 29 } 30 */ 31 32 bool listAppend(SqList& L, int e) 33 { 34 if (L.length == MAX_SIZE) return false; //存储空间已8满979438401111 35 L.elems[L.length] = e; 36 L.length++; //表长增1 37 return true; 38 } 39 40 bool listInsert(SqList & L, int i, int e) 41 { 42 if (i < 0 || i >= L.length)return false; //i 值不合法 43 if (L.length == MAX_SIZE) return false; //存储空间已满 44 for (int j = L.length - 1; j >= i; j--) 45 { 46 L.elems[j + 1] = L.elems[j]; //从最后一个元素开始后移,直到第i 个元 素后移 47 } 48 L.elems[i] = e; //将新元素e 放入第i 个位置 49 L.length++; //表长增1 50 return true; 51 } 52 53 bool listDelete(SqList & L, int i) 54 { 55 if (i < 0 || i >= L.length) return false; //不合法 56 if (i == L.length - 1) //删除最后一个元素,直接删除 57 { 58 L.length--; 59 return true; 60 } 61 for (int j = i; j < L.length - 1; j++) 62 { 63 L.elems[j] = L.elems[j + 1]; //被删除元素之后的元素前移 64 } 65 L.length--; 66 return true; 67 } 68 69 void listPrint(SqList & L) 70 { 71 cout << "顺序表元素size: " << L.size << ", 已保存元素个数length: " << L.length << endl; 72 for (int j = 0; j <= L.length - 1; j++) 73 { 74 cout << L.elems[j] << " "; 75 } 76 cout << endl; 77 } 78 79 void destroyList(SqList & L) 80 { 81 if (L.elems) delete[]L.elems;//释放存储空间 82 L.length = 0; 83 L.size = 0; 84 } 85 86 int main() 87 { 88 SqList list; 89 int i, e; 90 91 cout << "顺序表初始化..." << endl; 92 //1. 初始化 93 if (initList(list)) { 94 cout << "顺序表初始化成功!" << endl; 95 } 96 97 //2. 添加元素 98 int count = 0; 99 cout << "请输入要添加的元素个数:"; 100 cin >> count; 101 for (int i = 0; i < count; i++) { 102 cout << "\n 请输入要添加元素e:"; 103 cin >> e; 104 if (listAppend(list, e)) { 105 cout << "添加成功!" << endl; 106 } 107 else { 108 cout << "添加失败!" << endl; 109 } 110 } 111 112 listPrint(list); 113 114 //3. 插入元素 115 cout << "请输入要插入的位置和要插入的数据元素e:"; 116 cin >> i >> e; 117 if (listInsert(list, i, e)) { 118 cout << "插入成功!" << endl; 119 } 120 else { 121 cout << "插入失败!" << endl; 122 } 123 124 listPrint(list); 125 126 //4. 删除元素 127 cout << "请输入要删除的位置i:"; 128 cin >> i; 129 if (listDelete(list, i)) { 130 cout << " 删除成功!" << endl; 131 } 132 else { 133 cout << "删除失败!" << endl; 134 } 135 136 listPrint(list); 137 138 //5. 销毁 139 cout << "顺序表销毁..." << endl; 140 destroyList(list); 141 system("pause"); 142 return 0; 143 }
7. 企业级应用案例
高并发WEB 服务器中顺序表的应用高性能的web 服务器Squid 每秒可处理上万并发的请求,从网络连接到服务器的客户端与服务器端在交互时会保持一种会话(和电话通话的场景类似)。服务器端为了管理好所有的客户端连接,给每个连接都编了一个唯一的整数编号,叫做文件句柄,简称fd.
为了防止某些恶意连接消耗系统资源,当某个客户端连接超时(在设定的一定时间内没有发送数据)时,服务器就需要关闭这些客户端的连接.
具体实现方案:
1. 当有新的请求连到服务器时,如果经过服务器频率限制模块判断,貌似恶意连接,则使用顺序表来保存此连接的超时数据,超时值使用时间戳来表示,时间戳是指格林威治时间1970 年01 月01 日00 时00 分00 秒(相当于北京时间1970 年01 月01 日08 时00 分00 秒)起至现在的总秒数,其结构体定义如下:
1 typedef struct 2 { 3 int fd; 4 time_t timeout; // 使用超时时刻的时间戳表示 5 }ConnTimeout;
2. 服务器程序每隔一秒钟扫描一次所有的连接,检查是否超时,如果存在超时的连接,就关闭连接,结束服务,同时将顺序表中的记录清除!
======================================================================================================================