存在唯一的一个被称为“第一个”的数据元素;
存在唯一的一个被称为“最后一个”的数据元素;
除第一个之外,集合中的每一个数据元素都只有一个前驱;
除最后一个之外,集合中的每一个数据元素都只有一个后继;
线性表是最简单最常用的一种线性表。
线性表分为顺序表和链表。
顺序表又分为定长顺序表和不定长顺序表。
typedef struct SqList
{
int elem[10];
int length;
}SqList;
结构示意图如下:
//不定长顺序表的实现
#include "sqlist.h"
#include
#include//初始化
void InitSqlist(PSQList ps)
{
assert(ps != NULL);
if (ps == NULL)
return;ps->length = 0;
}//判满
static bool IsFul(PSQList ps)
{
return ps->length == 10;
}//插入数据,在ps顺序表的pos位置插入val;
bool Insert(PSQList ps, int pos, int val)
{
assert(ps != NULL);
if (ps == NULL)
return false;if (pos<0 || pos>ps->length || IsFul(ps))
{
return false;
}
//把数据移动到后面
for (int i = ps->length - 1; i >= pos; i--)
{
ps->elem[i + 1] = ps->elem[i];
}
//插入数据
ps->elem[pos] = val;
//有效数据个数++;
ps->length++;
return true;
}//判空
bool IsEmpty(PSQList ps)
{
return ps->length == 0;
}//在ps中查找第一个key值,找到返回下标,没有找到返回-1;
int Search(PSQList ps, int key)
{
for (int i = 0; i < ps->length; i++)
{
if (key == ps->elem[i])
return i;
}
return -1;
}//删除pos位置的值
bool DelPos(PSQList ps, int pos)
{
assert(ps != NULL);
if (ps == NULL)
return false;if (pos<0 || pos>=ps->length)
{
return false;
}
//将后面的数据前移
for (int i = pos; i < ps->length - 1; i++)
{
ps->elem[i] = ps->elem[i + 1];
}
//有效数据个数--;
ps->length--;
return true;
}//删除第一个val的值
bool DelVal(PSQList ps, int val)
{
int i = Search(ps, val);
if (i < 0)
return false;return DelPos(ps, i);
}//返回key的前驱下标,如果不存在返回-1;
int GetPrio(PSQList ps, int key)
{
int i = Search(ps, key);
if (i <= 0)//注意头没有前驱
return -1;return i - 1;
}//返回key的后继下标,如果不存在返回-1;
int GetNext(PSQList ps, int key)
{
int i = Search(ps, key);
if (i < 0 || i == ps->length - 1)//注意,尾没有后继
return -1;return i + 1;
}//输出
void Show(PSQList ps)
{
assert(ps != NULL);
if (ps == NULL)
return;for (int i = 0; i < ps->length; i++)
{
printf("%d ", ps->elem[i]);
}
printf("\n");
}//清空数据
void Clear(PSQList ps)
{
ps->length = 0;
}//销毁整个内存
void Destroy(PSQList ps)
{
Clear(ps);
}
typedef struct DSQList{
int *elem;//动态内存的地址
int length;//有效数据的个数
int listsize;//总容量
}DSQList,*DPSQList;
不定长顺序表相对于定长顺序表多了一个可以扩容的部分;为了实现扩容,我们必须在定长顺序表的基础上加上一个总容量(否则我们实现不了顺序表的判满);结构示意图如下
#include
#include
#include
#define INIT_SIZE 10
//初始化
void InitSqlist(DPSQList ps)
{
assert(ps!=NULL);
if(ps==NULL)
return;
ps->elem = (int*)malloc(INIT_SIZE*sizeof(int));
ps->length = 0;
ps->listsize = INIT_SIZE;
}
//判满
static bool IsFull(DPSQList ps)
{
return ps->length == ps->listsize;
}
//扩容
static bool Inc(DPSQList ps)
{
ps->elem = (int*)realloc(ps->elem,ps->listsize*2*sizeof(int));
assert(ps->elem!=NULL);
ps->listsize*=2;
return true;
}
//插入数据,在ps表中pos位置插入val
bool Insert(DPSQList ps,int pos,int val)
{
assert(ps!=NULL);
if(ps==NULL)
return false;
if(pos<0||pos>ps->length)
{
return false;
}
if(IsFull(ps))
{
Inc(ps);
}
//将数据后移
for(int i = ps->length-1;i>=pos;i--)
{
ps->elem[i+1] = ps->elem[i];
}
//插入新数据
ps->elem[pos] = val;
//有效数据个数++
ps->length++;
return true;
}
//判空
bool IsEmpty(DPSQList ps)
{
return ps->length==0;
}
//在ps表中查找第一个key值,找到返回下表,没找到返回-1
int Search(DPSQList ps,int key)
{
assert(ps!=NULL);
if(ps==NULL)
return -1;
for(int i=0;i
length;i++) {
if(ps->elem[i]==key)
return i;
}
return -1;
}
//删除pos位置的值
bool DelPos(DPSQList ps,int pos)
{
assert(ps!=NULL);
if(ps==NULL)
return false;
if(pos<0||pos>ps->length)
return false;
//删除pos位置
for(int i = pos;i
length;i++) {
ps->elem[i] = ps->elem[i+1];
}
//有效位置个数--
ps->length--;
return true;
}
/
//删除第一个val的值
bool DelVal(DPSQList ps, int val)
{
int i = Search(ps, val);
if (i < 0)
return false;return DelPos(ps, i);
}//返回key的前驱下标,如果不存在返回-1;
int GetPrio(DPSQList ps, int key)
{
int i = Search(ps, key);
if (i <= 0)
return -1;return i - 1;
}//返回key的后继下标,如果不存在返回-1;
int GetNext(DPSQList ps, int key)
{
int i = Search(ps, key);
if (i < 0 || i == ps->length - 1)
return -1;return i + 1;
}//输出
void Show(DPSQList ps)
{
assert(ps != NULL);
if (ps == NULL)
return;
for (int i = 0; i < ps->length; i++)
{
printf("%d ", ps->elem[i]);
}
printf("\n");
}//清空数据
void Clear(DPSQList ps)
{
ps->length=0;
}/销毁整个内存
void Destroy(DPSQList ps)
{
free(ps->elem);
ps->elem = NULL;
ps->length = 0;
ps->listsize = 0;
ps = NULL;//无效的代码
}
以上为不定长顺序表的结构以及主要的作用
顺序表的特点:
1.插入数据的时间复杂度是O(n),如果是尾插时间复杂度是O(1);
2.删除数据的时间复杂度是O(n),如果是尾删时间复杂度是O(1);
3.通过下标访问数据时间复杂度是O(1);
顺序表逻辑上相邻的元素物理上也相邻,所以插入和删除操作需要移动大量元素;
存储密度大(高),每个结点只存储数据元素(对比链表);
随机访问:顺序表是一种支持随机存取的存储结构,根据起始地址加上元素的序号,可以在O(1)时间内找到指定的元素,这就是随机存取的概念;
(1)设顺序表ps中的数据元素递增有序。试写一算法,将x插入到顺序表的适当位置上,以保持该表的有序性.
//有序顺序表插入x;
bool InsertX(DPSQList ps, int x)
{
assert(ps != NULL);
if (ps == NULL)
{
return false;
}
int i;
for (i = 0; i < ps->length; i++)
{
if (ps->elem[i] > x)
{
break;
}
}
return Insert(ps,i,x);
}
(2)设 ListA=(a1,....am)和ListB=(b1,...bn)均为顺序表。试写一个比较ListA,ListB大小的算法,依次比较ListA,ListB元素的值,如果一样则继续比较,如果不一样则比较完成.
//顺序表比较大小
int DSqlistCmp(DPSQList listA, DPSQList listB)
{
int i;
for ( i = 0; i < listA->length && listB->length; i++)
{
if (listA->elem[i] != listB->elem[i])
{
return listA->elem[i] - listB->elem[i];
}
}
return listA->length - listB->length;
}
(3)试写一算法,实现顺序表的就地逆置,即利用原表的存储空间将线性表(a1,...an) 逆置为(an,...a1)
//逆置顺序表
void Reverse(DPSQList ps)
{
int tmp;
for (int i = 0, j = ps->length - 1; i < j; i++, j--)
{
tmp = ps->elem[i];
ps->elem[i] = ps->elem[j];
ps->elem[j] = tmp;
}
}