我们知道线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列,如果我们用一组地址连续的存储单元依次存储线性表中的数据元素,从而使逻辑上相邻的两个元素在物理位置上也相邻,那么我们称这种逻辑顺序与其物理位置相同的存储方式为顺序存储又称顺序表。
通过数组实现静态分配和动态分配
静态分配代码:
在静态分配时,由于数组的大小和空间事先以及固定,一旦空间占满,再加入新的数据就会产生溢出。
动态分配代码
其中malloc函数申请一整片连续的存储空间,其返回指向这片空间的头指针,将返回值强制转化为存储元素的类型,那么其返回的就是一个数组。
而在数组中,我们知道了头指针,而其又是连续存储空间,那么头指针加sizeof(ElemType)即为下一元素的位置(这也是malloc函数参数的由来,即初始大小*元素的大小),如果我们知道一个位序i,那么直接通过头指针地址加 i - 1(数组下标为零) * sizeof(ElemType)即可实现随机存储。所以用数组来描述线性表的顺序结构在合适不过了。
顺序表的插入操作
在插入操作中将第i个元素及之后的元素后移无疑是最关键的一步,其也表明插入算法的平均时间复杂度为O(n),同时保持了顺序表的特点——逻辑顺序与其物理顺序相同
往末尾插入元素,则位序为length + 1,所以位序i最大只能等于length + 1
顺序表的删除操作
和插入操作类似,将第i个位置后的元素前移决定了算法的平均时间复杂度为O(n)。(将元素前移则将目标元素覆盖即删除)
按位查找以及按值查找
按值查找同样平均时间复杂度为O(n)。(实际为一个求和过程)
代码实例
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
for(int i = 0; i < MaxSize; i++)
L.data[i] = 0; //设置默认值为零
L.length = 0; //设置表初始长度为零
}
//在L的位序i处插入元素e
bool ListInsert(SqList &L, int i, int e){
if(i < 1 || i > L.length + 1) return false;
if(L.length >= MaxSize) //当前存储空间已满,无法插入
return false;
for(int j = L.length; j >= i; j--) //将第i个元素及之后的元素后移
L.data[j] = L.data[j - 1];
L.data[i - 1] = e; //在位置i处放入e
L.length++;
return true;
}
bool ListDelete(SqList &L, int i, int &e){
if(i < 1 || i > L.length + 1) return false;
e = L.data[i - 1]; //引用被删除值于e
for(int j = i; j < L.length; j++)
L.data[j - 1] = L.data[j]; //将第i个元素后的元素前移
L.length--;
return true;
}
//按位查找
int GetElem(SqList L, int i){
if(!(i > 0 && i < L.length)) return 0;
return L.data[i - 1];
}
//按值查找
int locateElem(SqList L, int e){
for(int i = 0; i < L.length; i++)
if(L.data[i] == e)
return i + 1; //返回下标
return 0;
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L;
InitList(L);
for(int i = 1; i <= MaxSize / 2; i++){
ListInsert(L, i, i);
}
//在末尾插入元素6
ListInsert(L, L.length + 1, 6);
printElem(L);
int e = -1; //假设表中元素都大于等于0
if(ListDelete(L, 3, e))
printf("已删除第3个元素值,删除元素值为=%d\n", e);
else
printf("删除失败!\n");
printElem(L);
return 0;
}
位序为=0, 元素值为=1
位序为=1, 元素值为=2
位序为=2, 元素值为=3
位序为=3, 元素值为=4
位序为=4, 元素值为=5
位序为=5, 元素值为=6
已删除第3个元素值,删除元素值为=3
位序为=0, 元素值为=1
位序为=1, 元素值为=2
位序为=2, 元素值为=4
位序为=3, 元素值为=5
位序为=4, 元素值为=6
动态顺序表代码
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define InitSize 10
typedef struct{
int *data; //指向动态分配数组的指针
int MaxSize; //顺序表的最大容量
int length; //顺序表的当前长度
}SeqList;
//初始化
void InitList(SeqList &L){
L.data = (int *)malloc(InitSize * sizeof(int));
L.length = 0; //设置表初始长度为零
L.MaxSize = InitSize;
}
//增加动态数组的长度
void IncreaseSize(SeqList &L, int len){
int *p = L.data;
L.data = (int *)malloc((L.MaxSize + len) * sizeof(int));
for(int i = 0; i < L.length; i++)
L.data[i] = p[i]; //将数据迁移到新区域
L.MaxSize += len; //库容len长度
free(p);
}
//在L的位序i处插入元素e
bool ListInsert(SeqList &L, int i, int e){
if(i < 1 || i > L.length + 1) return false;
if(L.length >= L.MaxSize) //当前存储空间已满
IncreaseSize(L, InitSize / 2);
for(int j = L.length; j >= i; j--) //将第i个元素及之后的元素后移
L.data[j] = L.data[j - 1];
L.data[i - 1] = e; //在位置i处放入e
L.length++;
return true;
}
bool ListDelete(SeqList &L, int i, int &e){
if(i < 1 || i > L.length + 1) return false;
e = L.data[i - 1]; //引用被删除值于e
for(int j = i; j < L.length; j++)
L.data[j - 1] = L.data[j]; //将第i个元素后的元素前移
L.length--;
return true;
}
//按位查找
int GetElem(SeqList &L, int i){
if(!(i > 0 && i < L.length)) return 0;
return L.data[i - 1]; //随机存取
}
//按值查找
int locateElem(SeqList L, int e){
for(int i = 0; i < L.length; i++)
if(L.data[i] == e)
return i + 1; //返回下标
return 0;
}
void printElem(SeqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SeqList L;
InitList(L);
for(int i = 1; i <= L.MaxSize - 1; i++){
ListInsert(L, i, i);
}
ListInsert(L, L.length + 1, 10);
printf("扩容前前list的最大容量为%d\n", L.MaxSize);
ListInsert(L, L.length + 1, 11);
printf("扩容后前list的最大容量为%d\n", L.MaxSize);
printElem(L);
bool flag = true;
for(int i = 3; i <= 5; i++){
int e = -1; //假设表中元素都大于等于0
if(!ListDelete(L, 3, e)) //被删除元素的下标不变
flag = false;
printf("元素=%d\t",e);
}
printf("\n");
if(flag)
printf("已删除[3,5]元素值\n");
else
printf("删除失败!\n");
printElem(L);
return 0;
}
在ListInsert函数中我们首先插入MaxSize - 1个元素,此时L.length = 9,则当前还可以插入位序为9,元素值为10(逻辑为data空间必须还有一个位置让当前元素插入);而当要插入位序为10,元素值为11时,L.length=10,则调用IncreaseSize函数。
扩容前前list的最大容量为10
扩容后前list的最大容量为15
位序为=0, 元素值为=1
位序为=1, 元素值为=2
位序为=2, 元素值为=3
位序为=3, 元素值为=4
位序为=4, 元素值为=5
位序为=5, 元素值为=6
位序为=6, 元素值为=7
位序为=7, 元素值为=8
位序为=8, 元素值为=9
位序为=9, 元素值为=10
位序为=10, 元素值为=11
元素=3 元素=4 元素=5
已删除[3,5]元素值
位序为=0, 元素值为=1
位序为=1, 元素值为=2
位序为=2, 元素值为=6
位序为=3, 元素值为=7
位序为=4, 元素值为=8
位序为=5, 元素值为=9
位序为=6, 元素值为=10
位序为=7, 元素值为=11
删除顺序表中最小值元素(假设唯一)
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
/*for(int i = 0; i < MaxSize; i++)
L.data[i] = 0; //设置默认值为零*/
L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 2;
L.data[3] = 5;
L.data[4] = 6;
L.length = 5; //设置表初始长度为零
}
bool Del_Min(SqList &L, int &e){
if(L.length == 0) return false;
int min = L.data[0];
int imin = 0;
for(int i = 0; i < L.length; i++){
if(L.data[i] < min){
min = L.data[i];
imin = i;
}
}
e = min;
L.data[imin] = L.data[L.length - 1];
L.length--;
return true;
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L;
InitList(L);
int Min = 0;
Del_Min(L, Min);
printf("%d\n", Min);
printElem(L);
return 0;
}
关键在于你不仅需要记录最小值,还要记录最小值的下标,因为要与最后一个元素交换。
元素逆置模块
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
/*for(int i = 0; i < MaxSize; i++)
L.data[i] = 0; //设置默认值为零*/
L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 2;
L.data[3] = 5;
L.data[4] = 6;
L.data[5] = 7;
L.length = 6; //设置表初始长度为零
}
void Reverse(SqList &L){
for(int i = 0; i < (L.length) / 2; i++){
int temp = L.data[i];
L.data[i] = L.data[L.length - 1 - i];
L.data[L.length - 1 - i] = temp;
}
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L;
InitList(L);
Reverse(L);
printElem(L);
return 0;
}
删除顺序表中所有值为x的元素
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
using namespace std;
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
/*for(int i = 0; i < MaxSize; i++)
L.data[i] = 0; //设置默认值为零*/
L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 2;
L.data[3] = 5;
L.data[4] = 6;
L.data[5] = 2;
L.length = 6; //设置表初始长度为零
}
void Delete_X(SqList &L, int x){
int k = 0;
for(int i = 0; i < L.length; i++){
if(L.data[i] != x){
L.data[k] = L.data[i];
k++;
}
}
L.length = k;
}
void Delete_X1(SqList &L, int x){
int k = 0;
for(int i = 0; i < L.length; i++)
if(L.data[i] == x)
k++;
else{
L.data[i - k] = L.data[i];
}
L.length -= k;
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L;
InitList(L);
Delete_X(L, 2);
printElem(L);
return 0;
}
我们可以把所有值为x的元素移动到末尾,但是你不知道交换的值是否也为x;所以我们可以把所有不是x的值移到开头,记录length即可;要满足O(n)的条件,我们可以不必把所有值为x的元素移到末尾,只需要把下一个不是x的元素将其覆盖即可,而这需要保持环境,即记录前移几个位置(k)。
删除有序表中[s,t]区间的值
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
using namespace std;
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
for(int i = 0; i < MaxSize; i++)
L.data[i] = i; //设置默认值为零
/*L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 2;
L.data[3] = 5;
L.data[4] = 6;
L.data[5] = 2;*/
L.length = MaxSize; //设置表初始长度为零
}
bool Del_S_T(SqList &L, int s, int t){
int i = 0, j = 0;
for(i; i < L.length && L.data[i] < s; i++);
if(i >= L.length) return false;
for(j = i; j < L.length && L.data[j] <= t; j++);
for(i, j; j < L.length; i++, j++){
L.data[i] = L.data[j];
}
//i此时为元素值第一个大于大于s的下标,j为元素值第一个小于t的下标
L.length = i;
//最后length为i与j交换的元素个数加上第一个大于大于s的下标,则为当前的下标i
return true;
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L;
InitList(L);
Del_S_T(L, 3, 4);
printElem(L);
return 0;
}
删除顺序表中[s,t]的值
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
using namespace std;
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
/*for(int i = 0; i < MaxSize; i++)
L.data[i] = i; //设置默认值为零*/
L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 5;
L.data[3] = 5;
L.data[4] = 6;
L.data[5] = 7;
L.length = 6; //设置表初始长度为零
}
bool Del_Same(SqList &L){
int i = 0, j = 1;
for(i, j; j < L.length; j++){
if(L.data[i] != L.data[j]){
//cout << i <<" "<<j<<endl;
L.data[++i] = L.data[j];
//cout << i <<" "<<j<<endl;
}
}
L.length = i + 1;
return true;
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L;
InitList(L);
Del_Same(L);
printElem(L);
return 0;
}
只需要将删除给定值x改为[s,t]区间即可
看待一件事情时,你不仅仅需要从正面去了解,还需要从反面去思考。在有序表上,删除值相同的元素;我们如果记录两个不同值的位序,其相减为1,则这两个中没有重复元素,即L.data[++i] = L.data[j]; 其中++i 等于 j,相反我们只需在后续循环中把每个元素前移 j - i 个元素即可即可。
在这里我们还需要注意i++与++i的特性即i++ 返回原来的值,++i 返回加1后的值,为了满足交换逻辑我们选择++i。
将两个有序表合并为一个新的有序顺序表
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
using namespace std;
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
/*for(int i = 0; i < MaxSize; i++)
L.data[i] = i; //设置默认值为零*/
L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 5;
L.data[3] = 5;
L.data[4] = 6;
L.data[5] = 7;
L.length = 6; //设置表初始长度为零
}
SqList Merge(SqList &L1, SqList &L2){
int i = 0, j = 0, k = 0;
SqList L3;
while(i < L1.length && j < L2.length){
if(L1.data[i] <= L2.data[j])
L3.data[k++] = L1.data[i++];
else
L3.data[k++] = L2.data[j++];
}
while(i < L1.length)
L3.data[k++] = L1.data[i++];
while(j < L2.length)
L3.data[k++] = L2.data[j++];
L3.length = k;
return L3;
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L1, L2;
L1.data[0] = 1; L1.data[1] = 3;
L1.data[2] = 5; L1.data[3] = 7;
L2.data[0] = 2;L2.data[1] = 4;
L2.data[2] = 6;L2.data[3] = 8;
L1.length = 4; L2.length = 4;
//InitList(L1); InitList(L2);
SqList L3;
L3 = Merge(L1, L2);
printElem(L3);
return 0;
}
交换一个有序表中的两个区间
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define MaxSize 10
using namespace std;
typedef struct{
int data[MaxSize]; //使用静态数组存放数据元素
int length;
}SqList;
//初始化
void InitList(SqList &L){
/*for(int i = 0; i < MaxSize; i++)
L.data[i] = i; //设置默认值为零*/
L.data[0] = 3;
L.data[1] = 4;
L.data[2] = 5;
L.data[3] = 5;
L.data[4] = 6;
L.data[5] = 7;
L.length = 6; //设置表初始长度为零
}
void Reverse(SqList &L, int left, int right){
int mid = (left + right) / 2;
for(int i = 0; i < mid - left; i++){
int temp = L.data[left + i];
L.data[left + i] = L.data[right - i];
L.data[right - i] = temp;
}
}
void ExChange(SqList &L, int m, int n){
Reverse(L, 0, m + n - 1);
Reverse(L, 0, n - 1);
Reverse(L, n, m + n - 1);
}
void printElem(SqList L){
for(int i = 0; i < L.length; i++){
printf("位序为=%d, 元素值为=%d\n", i, L.data[i]);
}
}
int main(){
SqList L;
InitList(L);
ExChange(L, 3, 3);
printElem(L);
return 0;
}