最近已经开始了王道单科书的学习,但是学习进度很慢,嘿嘿,开学已经第三周了才更新出来线性表的顺序存储代码,由于线性表的顺序存储之前的文章已经介绍过,在此便不再继续展开介绍。
以下是王道的数据结构线性表顺序存储实现代码和课后习题代码,仅供大家参考:
线性表的主要操作和课后习题函数列表
//一般线性表的基本操作
int InitList(SqList &L); //初始化线性表
int Empty(SqList &L); //线性表判空
void PrintList(SqList &L); //输出线性表
int Length(SqList L); //求表长
int DestroyList(SqList &L); //销毁线性表操作
int LocateElem(SqList L, ElemType e); //按值查找操作
ElemType GetElem(SqList L, int i); //按位查找操作
int ListInsert(SqList &L, int i, ElemType e); //插入操作
int ListDelete(SqList &L, int i, ElemType &e); //删除操作
//以下函数为王道课后综合题, 2021版王道《数据结构》
int DeleteMinValue(SqList &L, ElemType &e); //课后习题1
int ReverseList(SqList &L); //课后习题2
int DeleteSameValue(SqList &L, ElemType x); //课后习题3->实现方式1
int DeleteSameValue2(SqList &L, ElemType x); //课后习题3->实现方式2
int DeteteOrderST(SqList &L, ElemType s, ElemType t); //课后习题4
int DeleteST(SqList &L, ElemType s, ElemType t); //课后习题5
int DeleteSameValue06(SqList &L); //课后习题6
SqList MergeList(SqList &L1, SqList &L2, SqList &L3); //课后习题7
void ReverseSqList(SqList &L, int start, int end); //辅助函数反转线性表中从start至end的元素
void Test09(SqList &L, int m, int n); //课后习题8
int BinaryFindXIndex(SqList &L, int x); //辅助函数折半法查找
int FindXIndex(SqList &L, int x); //课后习题9
全部实现代码
#include<stdio.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define INFEASIBLE -1
#define OVERFLOW -2
//#define InitSize 100 //表长度的初始定义(动态开辟)
#define MaxSize 50 //定义线性表的最大长度
typedef int ElemType; //ElemType类型代替int型
typedef struct{
ElemType data[MaxSize]; //顺序表的元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义
//typedef struct{
// ElemType *data; //指示动态分配数组的指针
// int MaxSize, length; //数组的最大容量和当前指针
//}SeqList; //数组分配数组顺序表的类型定义
//一般线性表的基本操作
int InitList(SqList &L); //初始化线性表
int Empty(SqList &L); //线性表判空
void PrintList(SqList &L); //输出线性表
int Length(SqList L); //求表长
int DestroyList(SqList &L); //销毁线性表操作
int LocateElem(SqList L, ElemType e); //按值查找操作
ElemType GetElem(SqList L, int i); //按位查找操作
int ListInsert(SqList &L, int i, ElemType e); //插入操作
int ListDelete(SqList &L, int i, ElemType &e); //删除操作
//以下函数为王道课后综合题, 2021版王道《数据结构》
int DeleteMinValue(SqList &L, ElemType &e); //课后习题1
int ReverseList(SqList &L); //课后习题2
int DeleteSameValue(SqList &L, ElemType x); //课后习题3->实现方式1
int DeleteSameValue2(SqList &L, ElemType x); //课后习题3->实现方式2
int DeteteOrderST(SqList &L, ElemType s, ElemType t); //课后习题4
int DeleteST(SqList &L, ElemType s, ElemType t); //课后习题5
int DeleteSameValue06(SqList &L); //课后习题6
SqList MergeList(SqList &L1, SqList &L2, SqList &L3); //课后习题7
void ReverseSqList(SqList &L, int start, int end); //辅助函数反转线性表中从start至end的元素
void Test09(SqList &L, int m, int n); //课后习题8
int BinaryFindXIndex(SqList &L, int x); //辅助函数折半法查找
int FindXIndex(SqList &L, int x); //课后习题9
int main(){
SqList L1;
InitList(L1);
for(int i = 0; i < 20; i++)
ListInsert(L1, L1.length+1, 2*i);
PrintList(L1);
// DeleteSameValue06(L);
FindXIndex(L1, 4);
PrintList(L1);
return 0;
}
//初始化线性表
int InitList(SqList &L){
L.length = 0;
}
/**
插入操作
在顺序表L的第i(1<=i<=L.length+1)个位置插入新元素e
*/
int ListInsert(SqList &L, int i, ElemType e){
if(i < 1 || i > L.length+1) //判断i的范围是否有效
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++; //线性表长度加 1
return TRUE;
}
/**
删除操作
删除顺序表L中第i(1 <= i <= L.length)个位置的元素,并将删除元素的值带回
*/
int ListDelete(SqList &L, int i, ElemType &e){
if(i < 1 || i > L.length) //判断i的范围是否有效
return FALSE;
e = L.data[i-1]; //将被删除元素赋值给 e
for(int j = i; j < L.length; j++) //将第i个元素之后的元素依次进行前移
L.data[j-1] = L.data[j];
L.length--; //线性表长度减 1
return TRUE;
}
//判空操作
int Empty(SqList &L){
if(L.length <= 0)
return TRUE;
else
return FALSE;
}
/**
按值查找
在顺序表L中查找第一个元素值等于e的元素并返回其位序
*/
int LocateElem(SqList L, ElemType e){
for(int i = 0; i < L.length; i++){
if(L.data[i] == e)
return i+1; //下标为i元素值等于e,返回其为位序i+1
}
return 0;
}
//按位查找操作, 返回表中第i个位置的元素值
ElemType GetElem(SqList L, int i){
if(i < 1 || i > L.length)
return FALSE;
else
return L.data[i-1];
}
//求表长
int Length(SqList L){
return L.length;
}
//销毁操作,将顺序表清空销毁
int DestroyList(SqList &L){
int e = 0;
while(!Empty(L)){
//若顺序表不为NULL,进行循环删除操作,直至清空
ListDelete(L, 1, e);
}
return TRUE;
}
//输出操作
void PrintList(SqList &L){
if(Empty(L)){
//首先判断是否表空
printf("该线性表为空表.\n");
return;
}
printf("线性表L的所有元素值为:\n"); //输出线性表中所有元素的值
for(int i = 0; i < L.length; i++)
printf("%d\n", L.data[i]);
printf("输出完毕, 共有 %d 个数据.\n", L.length);
}
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------
以下函数为王道课后综合题, 2021版王道《数据结构》
*/
/*
1、 从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。
空出的位置由最后一个元素填补,若顺序表为空则显示出错信息并退出运行
*/
int DeleteMinValue(SqList &L, ElemType &e){
if(Empty(L)){
//若为空表,则输出错误信息并返回
printf("该表为空,删除失败!\n");
return FALSE;
}
int min = 0; //定义min,作为记录线性表最小值的下标,初始化为首元素
for(int i = 1; i < L.length; i++){
if(L.data[min] > L.data[i]) //通过循环 “打擂台 ”方式进行比较
min = i; // min不断刷新为最小值的下标
}
e = L.data[min]; //记录最小值并待返回
L.data[min] = L.data[L.length-1]; //将顺序表的最后一个元素填充至最小值位置,即删除
L.length--; //线性表长度减 1
return TRUE;
}
/*
2、 设计一个高效的算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)
*/
int ReverseList(SqList &L){
int temp = 0; //辅助变量
for(int i = 0; i < L.length/2; i++){
temp = L.data[i]; //交换L.data[i] 与 L.data[L.length-1-i]
L.data[i] = L.data[L.length-1-i];
L.data[L.length-1-i] = temp;
}
return OK;
}
/*
3、对长度为n的顺序表L,编写一个时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法删除线性表中所有值为x的数据元素。
*/
//第一种解法
int DeleteSameValue(SqList &L, ElemType x){
int i = 0, j = 0; //定义i作为变量遍历原线性表,j作为线性表中不为x的个数
for(i = 0; i < L.length; i++){
if(L.data[i] != x) //若线性表中元素不为x
L.data[j++] = L.data[i]; //生成不包括x的新线性表
}
L.length = j; //更新 新线性表的长度
return OK;
}
//第二种解法
int DeleteSameValue2(SqList &L, ElemType x){
int i = 0, k = 0; //k记录值等于x的元素的个数
while(i < L.length){
if(L.data[i] == x)
k++;
else
L.data[i-k] = L.data[i]; //当前元素前移k个单位
i++;
}
L.length = L.length - k; //顺序表L的长度更新
return TRUE;
}
/*
4、从有序顺序表中删除其值在给定值s与t之间(要求s<t)的所有元素,如果s或t不合适或顺序表为空,则显示出错信息并退出运行。
*/
int DeteteOrderST(SqList &L, ElemType s, ElemType t){
int i, j ;
if(s >= t || L.length <= 0){
printf("请检查输入参数s、t有误或线性表为空。\n");
return FALSE;
}
for(i = 0; i<L.length && L.data[i] < s; i++); //寻找值大于等于s的第一个元素
if(i >= L.length)
return FALSE; //若所有值均小于s则返回
for(j = i; j<L.length && L.data[j] <= t; j++); //寻找值大于t的第一个元素,即最后一个删除元素的下一个元素
for(;j < L.length; j++,i++){
L.data[i] = L.data[j]; //前移操作,填充被删元素位置
}
L.length = i;
return TRUE;
}
/*
5、从顺序表中删除其值在给定值s与t之间(包含s和t,要求s<t)的所有元素,如果s或t不合理或顺序表为空,显示出错信息并退出运行
*/
//该题与第三题非常类似,只是将判断条件稍作改变
int DeleteST(SqList &L, ElemType s, ElemType t){
int i = 0, k = 0; //i作为线性表遍历下标,k记录值等于值落在s、t之间元素的个数
if(s >= t || L.length <= 0){
printf("请检查输入参数s、t有误或线性表为空。\n");
return FALSE;
}
while(i < L.length){
if(L.data[i]>=s && L.data[i]<=t) //若k记录值等于值落在s、t之间
k++; //记录数累加
else
L.data[i-k] = L.data[i]; //当前元素前移k个单位
i++;
}
L.length = L.length-k;
return TRUE;
}
/*
6、从有序表中删除所有其值重复的元素,使表中所有元素的值不同
*/
int DeleteSameValue06(SqList &L){
int i = 1, j = 0;
for(i = 1;i < L.length; i++){
if(L.data[j] != L.data[i]){
L.data[++j] = L.data[i]; //特别注意,++j和j++含义不同,++j指的是先下标累加再赋值,j++是先赋值再累加
}
}
L.length = j+1;
return OK;
}
/*
7、将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表
*/
SqList MergeList(SqList &L1, SqList &L2, SqList &L3){
if(L1.length == 0) //线性表L1的长度为0
return L2;
if(L2.length == 0) //线性表L2的长度为0
return L1;
if(L1.length == 0 && L2.length == 0) //线性表L1和L2的长度均为0
return L3;
int i = 0, j = 0, k = 0;
while(i < L1.length && j < L2.length){
//使用while()循环对有序线性表进行合并
if(L1.data[i] <= L2.data[j]) //若L1的值比L2的小,将L1元素值添加到L3之上
L3.data[k++] = L1.data[i++];
else //若L1的值比L2的大,将L2元素值添加到L3之上
L3.data[k++] = L2.data[j++];
}
while(i < L1.length) L3.data[k++] = L1.data[i++]; //对剩余的L1、L2线性表进行检索添加
while(j < L2.length) L3.data[k++] = L2.data[j++];
L3.length = k; //更新线性表的长度
return L3;
}
/*
8、已知在一维数组A[m+n]中依次存放两个线性表(a1,a2,a3,...,Am)和(b1,b2,b3,...,Bn),试编写一个函数,将数组中两个顺序表
的位置互换,即将(b1,b2,b3,...,Bn) 放在 (a1,a2,a3,...,Am)的前面
*/
//作为辅助函数,交换线性表中第start(下标)到end(下标)位置的元素
void ReverseSqList(SqList &L, int start, int end){
if(start >= end)
return;
int mid = (start + end)/2, temp = 0;
while(start <= mid){
//对start至end之间的元素进行反转
temp = L.data[start];
L.data[start++] = L.data[end];
L.data[end--] = temp;
}
}
//反转执行操作
void Test09(SqList &L, int m, int n){
ReverseSqList(L, 0, L.length-1); //首先,逆序整个线性表--->(Bn,...,b2,b1,Am,...,a3,a2,a1)
ReverseSqList(L, 0, n-1); //之后,逆序线性表中前半部分元素(Bn,...,b2,b1)---->(b1,b2,b3,...,Bn)
ReverseSqList(L, n, n+m-1); //最后,逆序线性表中前半部分元素(Am,...,a3,a2,a1)---->(a1,a2,a3,...,Am)
}
/*
9、线性表(a1,a2,a3,...,An)中的元素递增有序且按顺序存储于计算机内。要求设计一个算法,完成用最少时间在表中查找数值为x的元素,
若找到则将其与后继元素位置相交换,若找不到则将其插入表中并使表中元素仍递增有序。
*/
//作辅助函数折半法查找
int BinaryFindXIndex(SqList &L, int x){
if(L.length == 0) //异常判断
return -1;
int left = 0, right = L.length-1, mid; //定义left、right,左右夹击进行折半法查找
while(left <= right){
//left < right时,无法检索到边界的情况
mid = (left + right)/2;
if(L.data[mid] < x) //当mid小于x时
left = mid + 1; //left指针左移
else if(L.data[mid] > x) //当mid大于x时
right = mid - 1; //right指针右移
else
return mid+1; //返回查找成功坐标
}
return -1;
}
//问题的主调用函数
int FindXIndex(SqList &L, int x){
int temp = 0, result;
result = BinaryFindXIndex(L, x); //折半法查找元素,返回元素位序
if(result != -1 && result < L.length){
//若能够找到,则与其后元素进行交换
printf("检索成功,原次序为 %d , 正在与位置为 %d 的数据交换...\n", result, result+1);
temp = L.data[result-1];
L.data[result-1] = L.data[result];
L.data[result] = temp;
}
else //若找不到该元素,则将该元素插入原有有序顺序表
{
printf("未检索到查找的数据,正在插入...\n");
int i = 0;
for(i = 0; x >= L.data[i]; i++); //查找插入位置
ListInsert(L, i+1, x); //调用插入元素函数
}
return OK;
}