学习数据结构思维框架:
顺序表
用一段地址连续的存储单元一次存储单元依次存储数据元素的线性结构。
地址连续的空间,一般情况下采用数组,但数组有静态数组和动态数组。所以,顺序表一般也分为:静态顺序表和动态顺序表。
今天我们来看一下静态顺序表。
静态顺序表
静态顺序表即最大容量是确定的,存储数量有限。
静态顺序表的结构如下:
#define MAX_SIZE 10 //静态顺序表的最大容量
typedef int DataType; //将int重命名为DataType,便于后续的更改
typedef struct SeqList
{
DataType _arr[MAX_SIZE]; //数据域
int _sz; //顺序表当前元素的个数
}SeqList;
顺序表的一些基本操作如下所示:
void PrintSeqList(SeqList* pSeq);//打印
void InitSeqList(SeqList* pSeq);//初始化
void PushBack(SeqList* pSeq, DataType data);//尾部插入
void PopBack(SeqList* pSeq);//尾部删除
void PushFront(SeqList* pSeq, DataType data);//头部插入
void PopFront(SeqList* pSeq);//头部删除
int Find(SeqList* pSeq, DataType data);//查找指定元素
void Insert(SeqList* pSeq, int pos, DataType data);//指定位置的插入
void Erase(SeqList* pSeq, int pos);//删除指定位置元素
void Remove(SeqList* pSeq, DataType data);//删除第一次出现的指定元素
void RemoveAll(SeqList* pSeq, DataType data);//删除所有的指定元素
int Size(SeqList* pSeq);//返回顺序表的大小
int Empty(SeqList* pSeq);//判断顺序表是否为空
void BubbleSort(SeqList* pSeq);//冒泡排序
void SelectSort(SeqList* pSeq);//选择排序
void SelectSort_OP(SeqList* pSeq);//选择排序的优化
int BinarySearch(SeqList* pSeq, DataType data);//二分查找
int BinarySearch_R(SeqList* pSeq, DataType data);//二分查找的递归写法
0.顺序表的打印
//打印
void printSeqList(SeqList* pSeq)
{
int i = 0;
assert(pSeq);
for (i = 0; i < pSeq->sz; i++)
{
printf("%d ", pSeq->data[i]);
}
printf("\n");
}
1.顺序表的初始化
//顺序表的初始化 = 数据域初始化 + 顺序表当前元素个数的初始化
void InitSeqList(SeqList* pSeq)//初始化
{
//所传顺序表的地址不能为空
assert(pSeq);
pSeq->_sz = 0;
memset(pSeq->_arr, 0, MAX_SIZE*sizeof(DataType));
}
2.顺序表的尾部插入
就是给最后面插入元素–>我们可以知道pSeq->_sz就为顺序表中元素的个数–>可以通过pSeq->_sz来找最后一个元素–>具体见下图
//尾部插入
void PushBack(SeqList* pSeq, DataType data)
{
assert(pSeq);
//顺序表已满--->不能插入
if (pSeq->_sz == MAX_SIZE)
return;
//将元素插在后面 && 元素个数增加1
pSeq->_arr[pSeq->_sz++] = data;
}
3.尾部删除
与尾部插入大同小异—>只不过尾部删除只需要修改元素个数就行
//尾部删除
void PopBack(SeqList* pSeq)
{
assert(pSeq);
//顺序表为空--->不能删除
if (pSeq->_sz == 0)
return;
//元素个数减1--->即看不见要删除的元素就行
pSeq->_sz -= 1;
}
4.头部插入
因为要给头部插入元素,所以需要将头部位置的地方空留出来,需要将元素统一向后面搬运一位,再将元素插入头部,—>为防止元素被覆盖,需要将元素从最后一个开始后移一位
//头部插入
void PushFront(SeqList* pSeq, DataType data)
{
int i = 0;
assert(pSeq);
if (pSeq->_sz == MAX_SIZE)
return;
//将元素向后搬移一位-->为了防止元素被覆盖-->元素搬移摇动最后一个开始
for (i = pSeq->_sz - 1; i >= 0; --i)
{
pSeq->_arr[i + 1] = pSeq->_arr[i];
}
//将元素插入头部
pSeq->_arr[0] = data;
pSeq->_sz++;
}
5.头部删除
头部删除元素,与要将后面的元素前移一位,将元素个数减1
//头部删除
void PopFront(SeqList* pSeq)
{
int i = 0;
assert(pSeq);
if (pSeq->_sz == 0)
return;
//将元素前移一位--->从头部开始进行
for (i = 0; i < pSeq->_sz - 1; i++)
{
//因为是将后面的元素赋给前面的,所以最后一个应该是将pSeq->_sz-1的这个元素赋给前一个,所以i最大取pSeq->_sz-2
pSeq->_arr[i] = pSeq->_arr[i + 1];
}
//元素个数减1
pSeq->_sz--;
}
6.查找指定的元素
通过所给的data,遍历顺序表,找到后—>返回其下标,未找到—>返回-1
//查找指定元素
int Find(SeqList* pSeq, DataType data)
{
int i = 0;
assert(pSeq);
for (i = 0; i < pSeq->_sz; ++i)
{
if (pSeq->_arr[i] == data)//找到后返回其下标
return i;
}
return -1;//否则返回-1
}
7.指定位置插入元素
在指定位置插入元素,然阿甘这个位置的元素统一向后移动一位,然后将元素插入其中。
//指定位置的插入
void Insert(SeqList* pSeq, int pos, DataType data)
{
int i = 0;
assert(pSeq);
//判断所给下标是否有效
if (pos < 0 || pos >= pSeq->_sz)
return;
//判满
if (pSeq->_sz == MAX_SIZE)
return;
for (i = pSeq->_sz - 1; i >= pos; --i)
{
pSeq->_arr[i + 1] = pSeq->_arr[i];
}
pSeq->_arr[pos] = data;
pSeq->_sz++;
}
8.删除指定位置的元素
将指定位置的元素向前移动一位,再将元素个数减1
//删除指定位置元素
void Erase(SeqList* pSeq, int pos)
{
int i = 0;
assert(pSeq);
//判断所给下标是否有效
if (pos < 0 || pos >= pSeq->_sz)
return;
//判满
if (pSeq->_sz == 0)
return;
for (i = pos; i < pSeq->_sz; ++i)
{
pSeq->_arr[i] = pSeq->_arr[i + 1];
}
pSeq->_sz--;
}
9.删除第一次出现的指定元素
第一次出现的元素,就从头到尾遍历顺序表,相同跳出循环,删除元素即可
//删除第一次出现的指定元素
void Remove(SeqList* pSeq, DataType data)
{
int i = 0;
int pos = 0;
assert(pSeq);
//遍历搜索第一次出现的指定元素,找到后跳出循环
for (i = 0; i < pSeq->_sz; ++i)
{
if (pSeq->_arr[i] == data)
break;
}
//走到这里,没有找到元素,直接返回
if (pSeq->_sz == i)
return;
//向前移动一位,删除元素
for (; i < pSeq->_sz - 1; ++i)
{
pSeq->_arr[i] = pSeq->_arr[i + 1];
}
pSeq->_sz--;
}
10.删除出现的所有指定元素
遍历顺序表,利用count来记录被删除元素的的个数,遇到被删除指定元素—>count加1,如果不是—>根据count的个数,决定它前移多少位,最后,用顺序表中的元素个数减掉被删除指定元素的个数来更新顺序表元素个数
//删除所有的指定元素
void RemoveAll(SeqList* pSeq, DataType data)
{
int count = 0;
int i = 0;
assert(pSeq);
//遍历,利用count记录元素遇到几个指定的元素,来决定元素的移动位数
for (i = 0; i < pSeq->_sz; ++i)
{
//如果是指定元素--->不移动,count加1
if (pSeq->_arr[i] == data)
count++;
else //如果不是指定的元素--->利用count,向前移动count位
pSeq->_arr[i - count] = pSeq->_arr[i];
}
//最后将顺序表的元素个数 减掉 删除指定元素的个数
pSeq->_sz -= count;
}
11.返回顺序表的大小
顺序表中,有专门记录的顺序表的个数
//返回顺序表的大小
int Size(SeqList* pSeq)
{
assert(pSeq);
return pSeq->_sz;
}
12.判断顺序表是否为空
利用pSeq->sz与0比较,空–>返回1,非空–>返回0
//判断顺序表是否为空
int Empty(SeqList* pSeq)
{
assert(pSeq);
//空--->返回1,非空--->返回0
return 0 == pSeq->_sz;
}
13. 冒泡排序
双层循环,一层循环决定循环的总趟数,第二层循环用来比较两个相邻元素,如果大小错误就交换顺序。每次冒泡出一个最大值(最小值),比较至没有相邻元素需要交换,排序已经结束
//冒泡排序
void BubbleSort(SeqList* pSeq)
{
int i = 0;
int j = 0;
int status = 0;
assert(pSeq);
//总共需要的比较的趟数
for (i = 0; i < pSeq->_sz - 1; i++)
{
status = 0;
//每一趟比较的次数
for (j = 0; j < pSeq->_sz - 1 - i; j++)
{
//降序排序
if (pSeq->_arr[j] < pSeq->_arr[j + 1])
{
//交换这里可以封装一个小函数
Swap(pSeq->data + j, pSeq->data + j + 1);
//DataType tmp = pSeq->_arr[j];
//pSeq->_arr[j] = pSeq->_arr[j + 1];
//pSeq->_arr[j + 1] = tmp;
status = 1;//初始状态为0,如果该趟元素无序,则会将status改变为1
}
}
//一趟结束了status没有被改变,则证明此序列已经有序,可直接结束
if (status == 0)
return;
}
}
//交换函数
void Swap(DataType* px, DataType* py)
{
assert(px && py);
DataType* tmp = *px;
*px = *py;
*py = tmp;
}
14.选择排序
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的最后位置,直到全部待排序的数据元素排完。
//选择排序
void SelectSort(pSeqList pSeq)
{
int i = 0;
assert(pSeq);
for (i = 0; i < pSeq->sz; i++)
{
int j = 0;
DataType minpos = 0;//最小值的下标-->默认为首元素
//找出未排序中最小的下标
for (j = 0; j <= pSeq->sz - 1 - i; j++)
{
if (pSeq->data[minpos] > pSeq->data[j])
{
minpos = j;
}
}
if (minpos != pSeq->sz - 1 - i)
{
Swap(pSeq->data + minpos, pSeq->data + (pSeq->sz-1-i));
}
}
}
15.选择排序的优化
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的最后位置,直到全部待排序的数据元素排完。
我们可以知道,如果我从待排序中分别选出最大最小的元素,最大存放在最左端,最小的存放在最右端,不就将之前的操作减少了一半;
//选择排序的优化
void SelectSortOP(pSeqList pSeq)
{
int start = 0;
int end = pSeq->sz - 1;
assert(pSeq);
while (start < end)
{
int maxpos = start;
int minpos = start;
int i = 0;
for (i = start; i <= end; i++)
{
if (pSeq->data[maxpos] < pSeq->data[i])
maxpos = i;
if (pSeq->data[minpos] > pSeq->data[i])
minpos = i;
}
//最大的数与未排序中的数字第一个交换位置
if (maxpos != start)
{
Swap(pSeq->data + start, pSeq->data + maxpos);
}
//防止出现未排序中的第一个位置为最小值,如果是,要更新坐标
if (minpos == start)
{
minpos = maxpos;
}
//最小数与未排序中数字最后一个交换位置
if (minpos != end)
{
Swap(pSeq->data + end, pSeq->data + minpos);
}
start++;
end--;
}
}
16.二分查找
//二分查找
int BinarySearch(pSeqList pSeq, DataType data)
{
int left = 0;
int right = pSeq->sz - 1;
assert(pSeq);
if (pSeq->data[left] == data)
{
return left;
}
if (pSeq->data[right] == data)
{
return right;
}
while (left < right)
{
int mid = left + (right - left) / 2;
if (pSeq->data[mid] == data)
{
return mid;
}
else if (pSeq->data[mid] > data)//元素没在右半区域
{
right = mid - 1;//更改右边界
}
else if (pSeq->data[mid] < data)//元素没在左半区域
{
left = mid + 1;//更改左边界
}
}
//走到这里证明着min>=max,即没有找到元素
return -1;
}
17.二分查找的递归写法
//二分查找递归写法
int BinarySearch_R(pSeqList pSeq, int left, int right, DataType data)
{
assert(pSeq);
int mid = left + (right - left) / 2;
if (left > right)
return -1;
if (pSeq->data[mid] == data)
return mid;
else if (pSeq->data[mid] > data)
return BinarySearch_R(pSeq, left, mid - 1, data);
else if (pSeq->data[mid] < data)
return BinarySearch_R(pSeq, mid + 1, right, data);
}
程序的测试文件
//test.c
#include "SeqList.h"
//尾部插入和删除的测试
void Test_Back()
{
SeqList seq;
InitSeqList(&seq);
PushBack(&seq, 1);
PushBack(&seq, 2);
PushBack(&seq, 3);
PushBack(&seq, 4);
PushBack(&seq, 5);
printSeqList(&seq);
PopBack(&seq);
PopBack(&seq);
printSeqList(&seq);
}
//头部插入和删除的测试
void Test_Front()
{
SeqList seq;
InitSeqList(&seq);
PushFront(&seq, 1);
PushFront(&seq, 2);
PushFront(&seq, 3);
PushFront(&seq, 4);
PushFront(&seq, 5);
printSeqList(&seq);
PopFront(&seq);
PopFront(&seq);
printSeqList(&seq);
}
//查找指定元素(返回其下标)的测试
void TestFind()
{
SeqList seq;
int i = 0;
InitSeqList(&seq);
for (i = 0; i < 10; i++)
{
PushBack(&seq, i);
}
printSeqList(&seq);
int pos = Find(&seq, 34);
if (pos == -1)
{
printf("该顺序表中没有此元素\n");
}
else
{
printf("找到了,下标为:%d\n", pos);
}
}
//指定位置插入_删除的测试
void TestInsert()
{
SeqList seq;
InitSeqList(&seq);
int i = 0;
InitSeqList(&seq);
for (i = 0; i < 10; i++)
{
PushBack(&seq, i);
}
printSeqList(&seq);
Insert(&seq, 4, 10);
printSeqList(&seq);
Erase(&seq, 5);
printSeqList(&seq);
}
//删除指定元素的测试
void TestRemove()
{
SeqList seq;
InitSeqList(&seq);
PushBack(&seq, 1);
PushBack(&seq, 2);
PushBack(&seq, 1);
PushBack(&seq, 3);
PushBack(&seq, 4);
PushBack(&seq, 1);
printSeqList(&seq);
Remove(&seq, 10);
printSeqList(&seq);
}
//删除指定的元素出现的所有位置的测试
void TestRemoveAll()
{
SeqList seq;
InitSeqList(&seq);
PushBack(&seq, 1);
PushBack(&seq, 2);
PushBack(&seq, 1);
PushBack(&seq, 3);
PushBack(&seq, 4);
PushBack(&seq, 1);
PushBack(&seq, 5);
printSeqList(&seq);
RemoveAll(&seq, 1);
printSeqList(&seq);
}
void TestSize()
{
SeqList seq;
InitSeqList(&seq);
PushBack(&seq, 1);
PushBack(&seq, 2);
PushBack(&seq, 1);
PushBack(&seq, 3);
PushBack(&seq, 4);
PushBack(&seq, 1);
PushBack(&seq, 5);
printSeqList(&seq);
int SeqListSize = Size(&seq);
printf("SeqListSize = %d\n", SeqListSize);
}
void TestEmpty()
{
SeqList seq;
InitSeqList(&seq);
PushBack(&seq, 1);
PushBack(&seq, 2);
PushBack(&seq, 3);
PushBack(&seq, 4);
PushBack(&seq, 5);
printSeqList(&seq);
int ret = Empty(&seq);
if (ret == 1)
{
printf("顺序表为空\n");
}
}
//冒泡排序的测试
void TestBubbleSort()
{
SeqList seq;
InitSeqList(&seq);
int i = 0;
for (i = 10; i > 0; i--)
{
PushBack(&seq, i);
}
printSeqList(&seq);
//排序
BubbleSort(&seq);
printSeqList(&seq);
}
//快速排序的测试
void TestSelectSort()
{
SeqList seq;
InitSeqList(&seq);
int i = 0;
for (i = 0; i < 10; i++)
{
PushBack(&seq, i);
}
printSeqList(&seq);
排序
SelectSort(&seq);
printSeqList(&seq);
}
//快速排序优化的测试
void TestSelectSortOP()
{
SeqList seq;
InitSeqList(&seq);
int i = 0;
for (i = 0; i < 10; i++)
{
PushBack(&seq, i);
}
printSeqList(&seq);
//排序
SelectSortOP(&seq);
printSeqList(&seq);
}
//二分查找的测试
void TestBinarySearch()
{
SeqList seq;
InitSeqList(&seq);
int i = 0;
for (i = 0; i < 10; i++)
{
PushBack(&seq, i);
}
int ret = 0;
ret = BinarySearch(&seq, 7);
if (ret == -1)
{
printf("顺序表中没有此元素\n");
}
else
{
printf("找到了,下标为:%d\n", ret);
}
}
//二分查找递归的测试
void TestBinarySearch_R()
{
SeqList seq;
InitSeqList(&seq);
int i = 0;
for (i = 0; i < 10; i++)
{
PushBack(&seq, i);
}
int ret = 0;
ret = BinarySearch_R(&seq, 0, seq.sz-1, 9);
if (ret == -1)
{
printf("顺序表中没有此元素\n");
}
else
{
printf("找到了,下标为:%d\n", ret);
}
}
void test()
{
Test_Back();
//Test_Front();
//TestFind();
//TestInsert();
//TestRemove();
//TestRemoveAll();
//TestSize();
//TestEmpty();
//TestBubbleSort();
//TestSelectSort();
//TestSelectSortOP();
//TestBinarySearch();
//TestBinarySearch_R();
}
int main()
{
test();
system("pause");
return 0;
}