顺序表
数组描述方法将元素存储在一个数组中,用一个数学公式来确定每个元素存储的位置,即在数组中的索引。这是最简单的一种存储方式,所有元素依次存储在一片连续的存储空间中,这就是通常所说的顺序表。 --- 数据结构、算法与应用
顺序表的实现
线性表动态分配顺序存储结构
ps:为了方便修改数据元素的类型,使用了模板,可以方便修改线性表中的数据元素的类型;
#define LIST_INIT_SIZE 100 // 线性表存储空间的初始分配量
#define LISTNCREMENT 10 // 线性表存储空间的分配增量
template <class T>
struct SeqList
{
T* element; // 存储空间的基质
int capacity; // 线性表的当前分配的存储容量
int listSize;; // 线性表的当前长度
};
顺序表的基本操作
void initMenu(); // 初始化菜单
SeqList<int>* initList(); // 初始化线性表
bool distroyList(SeqList<int>*&); // 销毁线性表
bool clearList(SeqList<int>*&); // 清空线性表
bool isEmpty(SeqList<int>*&); // 判断是否为空
int getLength(SeqList<int>*&); // 得到线性表的当前长度
int getElement(SeqList<int>*&, int); // 得到指定位置的元素
int getIndex(SeqList<int>*&, int); // 得到元素的下标
int getPreElement(SeqList<int>*&, int); // 得到元素的前驱
int getSeqElement(SeqList<int>*&, int); // 得到元素的后继
bool insertElement(SeqList<int>*&, int, int); // 插入元素
bool deleteElement(SeqList<int>*&, int); // 删除元素
void showElement(SeqList<int>*&); // 遍历表中的所有元素
void megerList(SeqList<int>*&, SeqList<int>*&); // 合并两个线性表
自定义函数的实现
void initMenu() // 初始化菜单界面
{
cout << "*************************" << endl;
cout << "1---初始化线性表" << endl;
cout << "2---销毁线性表" << endl;
cout << "3---清空线性表" << endl;
cout << "4---判断线性表是否为空" << endl;
cout << "5---求线性表的长度" << endl;
cout << "6---获取线性表中指定位置的元素" << endl;
cout << "7---获取线性表元素的位置" << endl;
cout << "8---求前驱" << endl;
cout << "9---求后继" << endl;
cout << "10---在线性表指定位置插入元素" << endl;
cout << "11---删除线性表指定位置的元素" << endl;
cout << "12---显示线性表" << endl;
cout << "13---合并两个非递减有序的线性表" << endl;
cout << "14---退出程序(输入负数)" << endl;
cout << "*************************" << endl;
}
(1)线性表的初始化
初始化线性表,是指初始化一个空的线性表,里面的元素个数是0
SeqList<int>* initList() // 初始化线性表
{
SeqList<int>* MyList = new SeqList<int>();
try
{
MyList->element = new int[LIST_INIT_SIZE];
MyList->capacity = LIST_INIT_SIZE;
MyList->listSize = 0;
}
catch (bad_alloc)
{
cerr << "初始化失败!" << endl;
exit(1);
}
cout << "初始化成功!" << endl;
return MyList;
}
(2)销毁线性表 、清空线性表、判断是否为空、返回线性表的长度
销毁线性表:释放线性表的基地址,将capacity与listSize赋值为0
清空线性表:只需将listSize赋值为0
判断是否为空:只需判断listSize的值是否为0
返回线性表的长度:只需将listSize的值返回
bool distroyList(SeqList<int>*& arrayList) // 销毁线性表
{
bool isDistory = false;
delete arrayList->element;
arrayList->element = nullptr;
arrayList->capacity = 0;
arrayList->listSize = 0;
if (arrayList->element == nullptr)
{
isDistory = true;
}
return isDistory;
}
bool clearList(SeqList<int>*& arrayList) // 清空线性表
{
bool isClear = false;
arrayList->listSize = 0;
if (arrayList->listSize == 0)
{
isClear = true;
}
return isClear;
}
bool isEmpty(SeqList<int>*& arrayList) // 判断线性表是否为空
{
if (arrayList->listSize > 0)
{
return false;
}
return true;
}
int getLength(SeqList<int>*& arrayList) // 得到线性表的当前长度
{
return arrayList->listSize;
}
(3)获得对应位置的元素
int getElement(SeqList<int>*& arrayList, int index) // 得到对应位置的元素
{
if (index > arrayList->listSize || index < 0) // 判断用户输入的下标是否合法
{
return -1;
}
return arrayList->element[index - 1];
}
(4)获得线性表元素的下标
int getIndex(SeqList<int>*& arrayList, int num) // 得到元素的下标
{
for (int i = 0; i < arrayList->listSize; i++)
{
if (arrayList->element[i] == num)
{
return i;
}
}
return -1;
}
(5)获得前驱
遍历顺序表找到与用户输入元素相同的元素的下标,将该下标-1得到前驱,但要注意特殊情况即当该元素为第一个元素时,没有前驱。
int getPreElement(SeqList<int>*& arrayList, int num) // 得到元素的前驱
{
int temp = -2; // 用来记录元素前驱的下标
for (int i = 0; i < arrayList->listSize; i++)
{
if (arrayList->element[i] == num && i == 0)
{// 顺序表的第一个元素,没有前驱
return -1;
}
if (arrayList->element[i] == num)
{// 找到前驱
temp = i - 1;
break;
}
}
if (temp == -2)
{// 没有该元素
return -2;
}
return arrayList->element[temp];
}
(6)获得后继
遍历顺序表找到与用户输入元素相同的元素的下标,将该下标+1得到后继,但要注意特殊情况即当该元素为最后一个元素时,没有后继。
int getSeqElement(SeqList<int>*& arrayList, int num) // 得到元素的后继
{
int temp = -2; // 用来记录元素前驱的下标
for (int i = 0; i < arrayList->listSize; i++)
{
if (arrayList->element[i] == num && i == arrayList->listSize - 1)
{// 顺序表的最后一个元素,没有后继
return -1;
}
if (arrayList->element[i] == num)
{// 找到后继
temp = i + 1;
break;
}
}
if (temp == -2)
{// 没有该元素
return -2;
}
return arrayList->element[temp];
}
(7)插入元素
插入元素之前要判断线性表是否初始化(主函数中实现),插入的位置是否合法,顺序表是否已满。
在顺序表的第i个位置插入元素e,与数组的插入操作基本相同,将顺序表第i个位置之后的元素从后向前依次向后移动一个位置,然后将元素e插入第i个位置,在插入元素之后要将顺序表的当前长度listSize++,但要注意是从后往前依次移动元素,即:先移动最后一个元素,在移动倒数第二个元素,依次类推
bool insertElement(SeqList<int>*& arrayList, int index, int num) // 插入元素
{
if (index < 1 || index > arrayList->listSize + 1) // 判断插入的位置是否合法
{
return false;
}
if (arrayList->listSize >= arrayList->capacity) // 判断顺序表的空间是否已满
{
try
{
int* newbase = new int[LIST_INIT_SIZE + LISTNCREMENT]; // 重新分配新的空间
copy(arrayList->element, arrayList->element + LIST_INIT_SIZE, newbase); // 将顺序表的元素赋值给新的顺序表
arrayList->element = newbase;
arrayList->capacity += LISTNCREMENT;
}
catch (bad_alloc)
{
exit(OVERFLOW);
}
}
for (int i = arrayList->listSize - 1; i >= index - 1; i--) // 插入操作,同数组的插入
{
arrayList->element[i + 1] = arrayList->element[i];
}
arrayList->element[index - 1] = num;
arrayList->listSize++;
return true;
}
(8)删除元素
删除元素之前要判断线性表是否初始化(主函数实现),顺序表是否为空(主函数实现),删除的位置是否合法。
删除线性表中的第i个元素,与数组的删除操作基本相同,需要将表中第i个元素之后的元素依次向前移动一位,将前面的元素覆盖。移动元素时要将第i+1个元素移动到第i个位置,在将第i+2个元素移动i+1的位置,直到将最后一个元素移动到它的前一个位置,删除元素之后,将顺序表的当前长的listSize--;
bool deleteElement(SeqList<int>*& arrayList, int index) // 删除下表对应的元素
{
if (index < 1 || index > arrayList->listSize) // 判断用户输入的下标是否合法
{
return false;
}
for (int i = index - 1; i < arrayList->listSize; i++) // 删除操作,同数组的删除
{
arrayList->element[i] = arrayList->element[i + 1];
}
arrayList->listSize--;
return true;
}
(9)遍历线性表
void showElement(SeqList<int>*& arrayList) // 遍历线性表
{
cout << "该线性表的元素为:" << endl;
for (int i = 0; i < arrayList->listSize; i++)
{
cout << arrayList->element[i] << "\t";
}
cout << endl;
}
(10)合并两个非降序线性表
ps:该方法也是我自己在力扣上做题的时候学的,下面附上该方法的链接
void megerList(SeqList<int>*& arrayList, SeqList<int>*& myList) // 合并两个线性表
{ // myList 线性表在调用该函数前需要初始化,具体实现在主函数
int size1 = arrayList->listSize; // 记录arrayList的空间大小
int size2 = myList->listSize; // 记录myArray的空间大小
int len1 = size1 - 1;
int len2 = size2 - 1;
int len = size1 + size2 - 1;
// 以上声明均为了更方便的实现一下操作
// 合并两个非降序线性表前需要将两个线性表非降序排序
sort(arrayList->element, arrayList->element + size1);
sort(myList->element, myList->element + size2);
SeqList<int>* newList = new SeqList<int>(); // 新的线性表,用来存储两个线性表合并后的新表
newList->element = new int[size1 + size2]{ -1 };
newList->listSize = size1 + size2;
while (len1 >= 0 && len2 >= 0) // 合并两个线性表的具体实现
{
newList->element[len--] = arrayList->element[len1] > myList->element[len2] ? arrayList->element[len1--] : myList->element[len2--];
}
if (len1 >= 0)
{
copy(arrayList->element, arrayList->element + (len1 + 1), newList->element);
}
if (len2 >= 0)
{
copy(myList->element, myList->element + (len2 + 1), newList->element);
}
cout << "合并后的顺序表为:" << endl;
for (int i = 0; i < newList->listSize; i++)
{
cout << newList->element[i] << "\t";
}
cout << endl;
}
主函数的实现
int main()
{
initMenu();
SeqList<int>* arrayList = new SeqList<int>();
int choice;
cout << "请输入操作代码:";
cin >> choice;
while (choice > 0)
{
switch (choice)
{
case 1://初始化线性表空间
{
arrayList = initList();
break;
}
case 2://销毁线性表
{
bool isTrue = distroyList(arrayList);
if (isTrue)
{
cout << "销毁成功!" << endl;
}
else
{
cout << "销毁失败!" << endl;
exit(1);
}
break;
}
case 3://清空线性表
{
bool isTrue = clearList(arrayList);
if (isTrue)
{
cout << "清空成功!" << endl;
}
else
{
cout << "清空失败!" << endl;
exit(1);
}
break;
}
case 4://判断线性表是否为空
{
bool isTrue = isEmpty(arrayList);
if (isTrue)
{
cout << "该表为空" << endl;
}
else
{
cout << "该表不为空" << endl;
}
break;
}
case 5://求线性表的长度
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
cout << "线性表的长度为:" << getLength(arrayList) << endl;
break;
}
case 6://获取线性表中指定位置的元素
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
if (isEmpty(arrayList))
{
cout << "请先为顺序表添加元素!" << endl;
break;
}
int index;
cout << "请输入要查找元素的位置:";
cin >> index;
int temp = getElement(arrayList, index);
if (temp == -1)
{
cerr << "访问越界!" << endl;
}
else
{
cout << "该元素为:" << temp << endl;
}
break;
}
case 7://获取线性表元素的位置
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
if (isEmpty(arrayList))
{
cout << "请先为顺序表添加元素!" << endl;
break;
}
int num;
cout << "请输入您要查找的元素:";
cin >> num;
int temp = getIndex(arrayList, num);
if (temp == -1)
{
cerr << "线性表中没有该元素!" << endl;
}
else
{
cout << "该元素的下标为:" << temp << endl;
}
break;
}
case 8://求前驱
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
if (isEmpty(arrayList))
{
cout << "请先为顺序表添加元素!" << endl;
break;
}
int num;
cout << "请输入求前驱的元素:";
cin >> num;
int temp = getPreElement(arrayList, num);
if (temp == -1)
{
cout << "该元素没有前驱!" << endl;
}
else if (temp == -2)
{
cerr << "线性表中没有该元素!" << endl;
}
else
{
cout << "该元素的前驱为:" << temp << endl;
}
break;
}
case 9://求后继
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
if (isEmpty(arrayList))
{
cout << "请先为顺序表添加元素!" << endl;
break;
}
int num;
cout << "请输入求后继的元素:";
cin >> num;
int temp = getSeqElement(arrayList, num);
if (temp == -1)
{
cout << "该元素没有后继!" << endl;
}
else if (temp == -2)
{
cerr << "线性表中没有该元素!" << endl;
}
else
{
cout << "该元素的后继为:" << temp << endl;
}
break;
}
case 10://在线性表指定位置插入元素
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
int index, num;
cout << "请输入要插入的位置下标与元素(end of -1):";
cin >> index >> num;
while (index != -1)
{
bool isTrue = insertElement(arrayList, index, num);
if (!isTrue)
{
cerr << "错误插入!" << endl;
exit(1);
}
else
{
cout << "插入成功!" << endl;
cout << "请输入要插入的位置下标与元素(end of -1):";
cin >> index >> num;
}
}
break;
}
case 11://删除线性表指定位置的元素
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
if (isEmpty(arrayList))
{
cout << "该顺序表已空!" << endl;
break;
}
int index;
cout << "请输入要删除的位置:";
cin >> index;
bool isTrue = deleteElement(arrayList, index);
if (!isTrue)
{
cerr << "删除失败!" << endl;
exit(1);
}
else
{
cout << "删除成功!" << endl;
}
{}
break;
}
case 12://显示线性表
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
if (isEmpty(arrayList))
{
cout << "请先为顺序表添加元素!" << endl;
break;
}
showElement(arrayList);
break;
}
case 13://合并两个非递减有序的线性表
{
if (arrayList->element == nullptr)
{
cout << "请先初始化顺序表!" << endl;
break;
}
if (isEmpty(arrayList))
{
cout << "请先为顺序表添加元素!" << endl;
break;
}
cout << "自动创建一个新的线性表!" << endl;
SeqList<int>* myList = initList();
int index, num;
cout << "请输入要插入的位置下标与元素(end of -1):";
cin >> index >> num;
while (index != -1)
{
insertElement(myList, index, num);
cout << "请输入要插入的位置下标与元素(end of -1):";
cin >> index >> num;
}
megerList(arrayList, myList);
break;
}
default:
break;
}
Sleep(1000);
system("cls");
initMenu();
cout << "请输入操作代码:";
cin >> choice;
}
cout << "程序退出!" << endl;
return 0;
}
注:本人已测试过该代码,如要亲自测试该代码,请添加头文件
#include <iostream>
#include <algorithm>
#include <Windows.h>
最后:
本人是第一次发表文章,以上代码仅为个人写法,不喜勿喷,如有不足或错误的地方欢迎指正。如果文章对你有所帮助,欢迎点赞支持。欢迎转载。