顺序表
顾名思义,就是用一段连续的存储单元依次存储数据元素的线性结构 。
顺序表又分为静态顺序表和动态顺序表。
静态顺序表的基本操作:
https://blog.youkuaiyun.com/zhao_miao/article/details/81145855
下面我们来分析动态顺序表的基本操作:
我们要完成的基本操作是:
初始化
打印
尾部插入
尾部删除
头部插入
头部删除
查找指定元素
指定位置插入
删除指定位置元素
删除指定元素
删除所有的指定元素
返回顺序表的大小
判断顺序表是否为空
冒泡排序
选择排序
选择排序的优化
二分查找
二分查找递归写法
首先定义一个结构体
与静态顺序表不同,动态顺序表没有最大容量的限制,可以边使用边开辟,节省空间。
#define DataType int
typedef struct SeqList
{
DataType *data; //存放的数据
int sz; //有效元素的个数
int capacity; //容量
}SeqList,*qSeqL
由于顺序表里存放的元素的类型是未知的,所以将int重命名为DataType,若想在顺序表中存储其他类型的数据,只需将int修改为对应的类型即可。
初始化函数
初始化sz,capacity,以及指针data
void InitSeqList(qSeqList seq)
{
assert(seq);
//初始化sz
seq->sz = 0;
//初始化capacity
seq->capacity = 10;
//初始化data
seq->data = (DataType *)malloc(seq->capacity*sizeof(DataType));
if (seq->data == NULL)
{
printf("空间开辟失败!\n");
return;
}
}
将基础容量定为10,刚开始有效元素的个数为0;由于基础容量为10,所以开辟10个元素类型为DataType类型的空间。
开辟空间就一定会出现开辟失败的情况,所以在开辟空间之后一定要判断,空间是否创建成功!
打印
循环打印
void PrintSeqList(qSeqList seq)
{
assert(seq);
int i = 0; //循环变量
for (i = 0; i < seq->sz; i++)
{
printf("%d ", seq->data[i]);
}
printf("\n");
}
尾插法
插入前应先判断元素的总个数是否小于基础容量,若小于直接插入,若大于则需要增加空间。
void PushBackSeqList(qSeqList seq, DataType data)
{
assert(seq);
int ret = Check_Capacity(seq);
if (ret == 1)
{
seq->data[seq->sz] = data;
seq->sz++;
}
}
增容函数
static int Check_Capacity(qSeqList seq)
{
DataType *seqnew = NULL; //新空间的地址
int Newcapacity = 0;
//如果有效个数大于等于容量则增容
if (seq->sz >= seq->capacity)
{
Newcapacity = seq->capacity + 5;
seqnew = realloc(seq->data, Newcapacity*sizeof(DataType));
if (seq == NULL)
{
printf("空间开辟失败!\n");
return -1;
}
else
{
seq->data = seqnew; //新空间的地址交给原空间的地址
seq->capacity = Newcapacity; //容量更新
return 1;
}
}
//如果有效个数小容量则直接返回
else
return 1;
}
若要增容,在之前所开辟的后面追加空间,由于有失败的可能,所以新开辟的空间不可以用原来空间的地址,需要定义一个新的地址,如果开辟成功,则把这个地址赋给之前的那个空间地址。
尾删法
void PopBackSeqList(qSeqList seq)
{
if (seq->sz == 0)
{
printf("没有可以删除的数据了!\n");
return;
}
else
seq->sz--;
}
头插法
所有元素后移
void PushFrontSeqList(qSeqList seq, DataType data)
{
assert(seq);
int ret = Check_Capacity(seq); //判断是否可以插入
int i = 0;
if (ret == 1)
{
for (i = seq->sz - 1; i >= 0; i--) //元素后移
{
seq->data[i+1] = seq->data[i];
}
seq->data[0] = data;
seq->sz++;
}
}
头删法
所有元素前移
void PopFrontSeqList(qSeqList seq)
{
int i = 0;
if (seq->sz == 0)
{
printf("没有可以删除的数据了!\n");
return;
}
else
{
for (i = 1; i < seq->sz; i++) //元素前移
{
seq->data[i-1] = seq->data[i];
}
seq->sz--; //容量--
}
}
查找指定元素
int FindSeqList(qSeqList seq, DataType data)
{
int i = 0;
assert(seq);
for (i = 0; i < seq->sz; i++)
{
if (seq->data[i] == data)
return i;
}
return -1;
}
指定位置插入
指定位置以及之后的所有元素后移
void Insert(qSeqList seq, int pos, DataType data)
{
int i = 0;
assert(seq);
int ret = Check_Capacity(seq);
if (ret == 1)
{
for (i = seq->sz - 1;i>=pos; i--)
{
seq->data[i+1] = seq->data[i];
}
seq->data[pos] = data;
seq->sz++; //容量++
}
}
指定位置删除
指定位置之后的所有元素前移
void Erase(qSeqList seq, int pos)
{
int i = 0;
assert(seq);
if (seq->sz == 0)
{
printf("没有可以删除的数据!\n");
return;
}
for (i = pos + 1;i < seq->sz; i++)
{
seq->data[i - 1] = seq->data[i];
}
seq->sz--; //容量--
}
由于指定位置插入和指定位置删除都是在查找指定元素成立的条件下测试的,即是在pos合法的情况下插入和删除,所以不需要判断位置(pos)的合法性,如果不是在查找指定元素成立的条件下进行指定位置插入和删除就需要判断pos的合法性。
删除指定元素
void Remove(qSeqList seq, DataType data)
{
int i = 0;
int j = 0;
assert(seq);
for (i = 0; i < seq->sz; i++)
{
if (seq->data[i] == data)
break;
}
if (i < seq->sz) //i为指定元素的下标
{
//元素移动(i之后的元素前移)
for (j = i + 1; j < seq->sz; j++)
{
seq->data[j - 1] = seq->data[j];
}
seq->sz--;//容量--
}
else
printf("没有该元素!\n");
}
删除所有的指定元素
void RemoveAll(qSeqList seq, DataType data)
{
int i = 0;
int j = 0;
assert(seq);
for (i = 0; i < seq->sz; i++)
{
if (seq->data[i] == data)
{
//元素移动
for (j = i + 1; j < seq->sz; j++)
{
seq->data[j - 1] = seq->data[j];
}
seq->sz--;//容量--
}
}
}
返回顺序表的大小
int sizeSeqList(qSeqList seq)
{
return seq->sz;
}
返回顺序表是否为空
int EmptySeqList(qSeqList seq)
{
if (seq->sz == 0)
{
return -1; //空
}
return 0; //非空
}
冒泡排序
void Bubblesort(qSeqList seq)
{
int i = 0;
int j = 0;
int flag = 0;
assert(seq);
for (i = 0; i < seq->sz - 1; i++)
{
flag = 0;
for (j = 0; j < seq->sz - i-1; j++)
{
if (seq->data[j]>seq->data[j + 1])
{
//交换
swap(seq->data + j, seq->data + j + 1);
//用于节约时间,如果flag不改变,证明有序
flag = 1;
}
}
if (flag = 0)
{
return;
}
}
}
选择排序
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的最后位置,直到全部待排序的数据元素排完。
void SelectSort(qSeqList seq)
{
int maxpos = 0; //最大值下标
int i = 0;
int j = 0;
assert(seq);
for (i = 0; i < seq->sz; i++)
{
maxpos = 0;
for (j = 1; j < seq->sz - i; j++)
{
if (seq->data[j]>seq->data[maxpos])
maxpos = j;
}
if (maxpos != j - 1)
{
swap(seq->data + maxpos, seq->data + j - 1);
}
}
}
选择排序的优化
每一次从待排序的数据元素中选出最小和最大的两个元素,存放在序列的起始位置最后位置,直到全部待排序的数据元素排完
void SelectSort_OP(qSeqList seq)
{
int left = 0;
int right = seq->sz - 1;
int maxpos = 0; //最大值下标
int minpos = 0; //最小值下标
int i = 0;
assert(seq);
while (left <= right)
{
maxpos = left;
minpos = left;
//找出最大值和最小值
for (i = left + 1; i <= right; i++)
{
if (seq->data[i]>seq->data[maxpos])
maxpos = i;
if (seq->data[i]<seq->data[minpos])
minpos = i;
}
if (maxpos != right)
swap(seq->data + maxpos, seq->data + right);
//如果最小值在right指向的位置
//由于right指向的位置已经变成了最大值
//所以应该修改最小值的下标,使得其到原来最大值的地方
if (minpos == right)
minpos = maxpos;
if (minpos != left)
swap(seq->data + left, seq->data + minpos);
left++;
right--;
}
}
二分查找
int BinarySearch(qSeqList seq, DataType data)
{
int left = 0;
int right = seq->sz - 1;
int mid = 0;
while (left <= right)
{
mid = left + (right - left) / 2;
if (seq->data[mid] > data)
{
right = mid - 1;
}
else if (seq->data[mid] < data)
{
left = mid + 1;
}
else
return mid;
}
return -1;
}
二分查找递归写法
int BinarySearch_R(qSeqList seq, int left, int right, DataType data)
{
int mid = left + (right - left) / 2;
assert(seq);
if (left <= right)
{
if (seq->data[mid] > data)
{
return BinarySearch_R(seq, left, mid - 1, data);
}
else if (seq->data[mid] < data)
{
return BinarySearch_R(seq, mid + 1, right, data);
}
{
return mid;
}
}
return -1;
}
.h文件(函数声明)
#ifndef __SeqList_H__
#define __SeqList_H__
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define DataType int
typedef struct SeqList
{
DataType *data; //存放的数据
int sz; //有效元素的个数
int capacity; //容量
}SeqList,*qSeqList;
//初始化函数
void InitSeqList(qSeqList seq);
//打印函数
void PrintSeqList(qSeqList seq);
//尾部插入
void PushBackSeqList(qSeqList seq, DataType data);
//尾部删除
void PopBackSeqList(qSeqList seq);
//头部插入
void PushFrontSeqList(qSeqList seq, DataType data);
//头部删除
void PopFrontSeqList(qSeqList seq);
//查找指定元素
int FindSeqList(qSeqList seq, DataType data);
//指定位置插入
void Insert(qSeqList seq, int pos, DataType data);
//指定位置删除
void Erase(qSeqList seq, int pos);
//删除指定元素
void Remove(qSeqList seq, DataType data);
//删除全部指定元素
void RemoveAll(qSeqList seq, DataType data);
//返回顺序表的大小
int sizeSeqList(qSeqList seq);
//判断顺序表是否为空
int EmptySeqList(qSeqList seq);
//冒泡排序
void Bubblesort(qSeqList seq);
//选择排序
void SelectSort(qSeqList seq);
//选择排序的优化
void SelectSort_OP(qSeqList seq);
//二分查找
int BinarySearch(qSeqList seq, DataType data);
//二分查找递归
int BinarySearch_R(qSeqList seq,int left,int right, DataType data);
#endif //__SeqList_H__
.c测试文件
#include"SeqList.h"
SeqList seq; //定义一个全局变量seq
//测试尾部插入和尾部删除
void TestBack()
{
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 3);
//打印
PrintSeqList(&seq);
//尾部删除
PopBackSeqList(&seq);
PopBackSeqList(&seq);
//打印
PrintSeqList(&seq);
}
//测试头部插入和尾部删除
void TestFront()
{
//初始化
InitSeqList(&seq);
//头部插入
PushFrontSeqList(&seq, 3);
PushFrontSeqList(&seq, 2);
PushFrontSeqList(&seq, 1);
//打印
PrintSeqList(&seq);
//头部删除
PopFrontSeqList(&seq);
PopFrontSeqList(&seq);
//打印
PrintSeqList(&seq);
}
//测试查找指定元素
void TestFind()
{
int pos = 0;
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 3);
//打印
PrintSeqList(&seq);
//查找指定元素
pos = FindSeqList(&seq, 2);
if (pos == -1)
{
printf("没有找到!\n");
return;
}
else
{
printf("下标是:%d\n", pos);
//指定位置插入
Insert(&seq, pos, 4);
//打印
PrintSeqList(&seq);
//指定位置删除
Erase(&seq, pos);
//打印
PrintSeqList(&seq);
}
}
//测试删除指定元素
void TestRemove()
{
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 3);
//打印
PrintSeqList(&seq);
//删除指定元素
Remove(&seq, 3);
//打印
PrintSeqList(&seq);
}
//测试删除所有的指定元素
void TestRemoveAll()
{
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 3);
//打印
PrintSeqList(&seq);
//删除指定元素
RemoveAll(&seq, 3);
//打印
PrintSeqList(&seq);
}
//返回顺序表的大小
void TestSize()
{
int sz = 0;
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 3);
//打印
PrintSeqList(&seq);
sz = sizeSeqList(&seq);
printf("sz=%d\n", sz);
}
//判断顺序表是否为空
void TestEmpty()
{
int sz = 0;
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 3);
//打印
PrintSeqList(&seq);
sz = EmptySeqList(&seq);
if (sz == -1)
{
printf("顺序表为空!\n");
}
else
{
printf("顺序表不为空!\n");
}
}
//测试冒泡排序
void TestBubble()
{
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 6);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 4);
//打印
PrintSeqList(&seq);
Bubblesort(&seq);
//打印
PrintSeqList(&seq);
}
//测试选择排序
void TestSelectSort()
{
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 6);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 4);
PushBackSeqList(&seq, 1);
//打印
PrintSeqList(&seq);
SelectSort(&seq);
//打印
PrintSeqList(&seq);
}
//测试选择排序的优化
void TestSelectSort_OP()
{
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 6);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 4);
PushBackSeqList(&seq, 1);
//打印
PrintSeqList(&seq);
SelectSort_OP(&seq);
//打印
PrintSeqList(&seq);
}
//二分查找
void TestBinarySearch()
{
int pos = 0;
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 3);
//打印
PrintSeqList(&seq);
pos = BinarySearch(&seq, 1
);
if (pos == -1)
{
printf("没有找到!\n");
return;
}
else
{
printf("下标为:%d\n", pos);
}
}
//二分查找递归
void TestBinarySearch_R()
{
int pos = 0;
//初始化
InitSeqList(&seq);
//尾部插入
PushBackSeqList(&seq, 1);
PushBackSeqList(&seq, 2);
PushBackSeqList(&seq, 3);
PushBackSeqList(&seq, 4);
//打印
PrintSeqList(&seq);
pos = BinarySearch_R(&seq,0,seq.sz-1, 1);
if (pos == -1)
{
printf("没有找到!\n");
return;
}
else
{
printf("下标为:%d\n", pos);
}
}
void test()
{
//测试尾部插入和尾部删除
TestBack();
//测试头部插入和尾部删除
//TestFront();
//测试查找指定元素以及指定位置插入和指定位置删除
//TestFind();
//测试删除指定元素
//TestRemove();
//测试删除所有的指定元素
//TestRemoveAll();
//返回顺序表的大小
//TestSize();
//判断顺序表是否为空
//TestEmpty();
//测试冒泡排序
//TestBubble();
//测试选择排序
//TestSelectSort();
//测试选择排序的优化
//TestSelectSort_OP();
//二分查找
//TestBinarySearch();
//二分查找递归
//TestBinarySearch_R();
}
int main()
{
test();
system("pause");
return 0;
}