在学习了C语言之后,我们先来了解一下简单的数据结构,顺序表和链表。
顺序表和链表都属于线性数据结构。顺序表的底层相当于一个数组,因为它的空间是一段地址连续的存储单元;链表的底层不需要所有的空间都连续,只要通过指针就可以找到下一个存储空间。
下面就用C语言简单的实现一下静态顺序表和动态顺序表。
1、静态顺序表
SeqList.h
#ifndef __SQLLIST_H__
#define __SQLLIST_H__
#include<stdio.h>
#include<assert.h>
#include<string.h>
typedef int Datatype;
#define MAX 10
typedef struct SeqList
{
Datatype data[MAX];
int sz;
}SeqList, *pSeqlist;
void InitSeqList(pSeqlist ps); //初始化顺序表
void PushBack(pSeqlist ps, Datatype key); //尾部插入元素
void PopBack(pSeqlist ps); //尾部删除元素
void PushFront(pSeqlist ps, Datatype key); //头部插入元素
void PopFront(pSeqlist ps); //头部删除元素
int Find(pSeqlist ps, Datatype key); //查找指定元素,并返回下标
int Insert(pSeqlist ps, Datatype key, int pos); //在指定位置插入元素
void Remove(pSeqlist ps, Datatype key); //删除指定元素
void RemoveAll(pSeqlist ps, Datatype key);//删除指定的所有元素
void Reverse(pSeqlist ps); //逆置顺序表
void Sort(pSeqlist ps); //升序排序
int BinarSearch(pSeqlist ps, Datatype key); //二分查找指定元素
#endif
SeqList.c
#include"SeqList.h"
void InitSeqList(pSeqlist ps)
{
ps->sz = 0;
memset(ps->data, 0, sizeof(ps->data));
}
void Display(const pSeqlist ps)
{//打印顺序表中的元素
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
printf("%d ", ps->data[i]);
}
printf("\n");
}
void PushBack(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
if (ps->sz == MAX)
{
return;
}
ps->data[ps->sz] = key;
ps->sz++;
}
void PopBack(pSeqlist ps)
{
assert(ps != NULL);
if (ps->sz == 0)
{
return;
}
ps->sz--;
}
void PushFront(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
if (ps->sz == MAX)
return;
if (ps->sz < MAX)
{
int i = 0;
//memmove(目标,源,字节数)
memmove(ps->data + 1, ps->data, sizeof(Datatype)*(ps->sz));
/*for (i = ps->sz; i>0; i--)
{ 将从最后一个元素开始,每个元素往后挪一个
ps->data[i] = ps->data[i - 1];
}*/
ps->data[0] = key;
ps->sz++;
}
}
void PopFront(pSeqlist ps)
{
int i = 0;
assert(ps != NULL);
if (ps->sz == 0)
return;
for (i = 0; i<ps->sz - 1; i++)
{ //从第二个元素开始,每个都往前挪一个
ps->data[i] = ps->data[i + 1];
}
ps->sz--;
}
int Find(pSeqlist ps, Datatype key)
{
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
if (key == ps->data[i])
return i;
}
return -1;
}
int Insert(pSeqlist ps, Datatype key, int pos)
{
int i = 0;
assert(ps != NULL);
if (ps->sz == MAX)
return;
if (ps->sz < MAX)
{
for (i = ps->sz; i >pos; i--)
{
ps->data[i] = ps->data[i - 1];
}
ps->data[pos] = key;
ps->sz++;
}
}
void Remove(pSeqlist ps, Datatype key)
{
int pos = 0;
assert(ps);
pos = Find(ps, key);
if (pos != -1)
{
memmove(ps->data + pos, ps->data + pos + 1, (ps->sz - pos - 1)*sizeof(Datatype));
ps->sz--;
}
}
void RemoveAll(pSeqlist ps, Datatype key)//删除所有的key
{
int pos = 0;
assert(ps);
while ((pos = Find(ps, key)) != -1)
{
Remove(ps, key);
}
}
void Swap(Datatype *a, Datatype *b)
{
Datatype tmp = *a;
*a = *b;
*b = tmp;
}
void Reverse(pSeqlist ps)
{
Datatype* left = ps->data;
Datatype* right = ps->data + ps->sz - 1;
assert(ps != NULL);
while (left < right)
{
Swap(left, right);
left++;
right--;
}
}
void Sort(pSeqlist ps)
{
int i = 0;
int j = 0;
assert(ps);
for (i = 0; i < (ps->sz - 1); i++)
{
for (j = 0; j < ps->sz - 1 - i; j++)
{
if (ps->data[j] > ps->data[j + 1])
{
Swap(&ps->data[j], &ps->data[j + 1]);
/*Datatype tmp = ps->data[j];
ps->data[j ] = ps->data[j+1];
ps->data[j + 1] = tmp;*/
}
}
}
}
int BinarSearch(pSeqlist ps, Datatype key)
{
int left = 0;
int right = ps->sz - 1;
assert(ps);
while (left <= right)
{
int mid = left + ((right - left) >> 1);
if (key == ps->data[mid])
{
return mid;
}
else if (key > ps->data[mid])
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return -1;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void test1()//尾插尾删
{
SeqList my_list;
InitSeqList(&my_list);
PushBack(&my_list, 1);
PushBack(&my_list, 2);
PushBack(&my_list, 3);
PushBack(&my_list, 4);
Display(&my_list);
PopBack(&my_list);
Display(&my_list);
PopBack(&my_list);
Display(&my_list);
PopBack(&my_list);
Display(&my_list);
}
void test2()//头插头删
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
}
void test3()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
PushFront(&my_list, 5);
pos = Find(&my_list, 4);
if (pos == -1)
{
printf("要查找的u元素不存在");
}
else
{
Insert(&my_list, 6, pos);
}
Display(&my_list);
}
void test4()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 3);
PushFront(&my_list, 5);
PushFront(&my_list, 4);
PushFront(&my_list, 2);
Display(&my_list);
Sort(&my_list);
Display(&my_list);
}
void test5()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
PushFront(&my_list, 5);
Display(&my_list);
Sort(&my_list);
pos = BinarSearch(&my_list, 3);
printf("%d\n", pos);
pos = BinarSearch(&my_list, 6);
printf("%d\n", pos);
}
int main()
{ //对顺序表中锁实现函数的简单测试
test5();
system("pause");
return 0;
}
这是简单的实现了一个静态的顺序表,但它是有缺陷的,就是他的数组大小是固定的,接下来我们就来实现一个动态的也就是数组大小可变的顺序表。
2、动态顺序表
在编写动态顺序表的时候,更多的是要检测在插入元素时是否需要增容。在定义顺序表时,不仅需要一个数组的大小sz,还需要一个容量capacity,当sz<capacity时,不需要增容,而当sz==capacity时,就需要动态增容,然后再插入元素。
SeqList.h
#ifndef __SQLLIST_H__
#define __SQLLIST_H__
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#define DEFAULT_SZ 3
#define INC 3
typedef int Datatype;
typedef struct SeqList
{
Datatype* data;
int sz;
int capacity;
}SeqList,*pSeqlist;
void InitSeqList(pSeqlist ps);
void PushBack(pSeqlist ps, Datatype key);
void PopBack(pSeqlist ps);
void PushFront(pSeqlist ps, Datatype key);
void PopFront(pSeqlist ps);
int Find(pSeqlist ps, Datatype key);
int Insert(pSeqlist ps, Datatype key, int pos);
void Remove(pSeqlist ps, Datatype key);
void RemoveAll(pSeqlist ps, Datatype key);//删除所有的key
void Reverse(pSeqlist ps);
void Sort(pSeqlist ps);
int BinarSearch(pSeqlist ps, Datatype key);
#endif
SeqList.c
#include"SeqList.h"
void InitSeqList(pSeqlist ps)
{ //初始化:元素个数为0,容量为DEFAULT_SZ
assert(ps);
ps->sz = 0;
ps->capacity = DEFAULT_SZ;
ps->data = malloc((ps->capacity)*sizeof(Datatype));
if (ps->data == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
memset(ps->data, 0, (ps->capacity)*sizeof(Datatype));
}
void Destroy(pSeqlist ps)
{
assert(ps);
free(ps->data);
ps->data = NULL;
ps->capacity = 0;
ps->sz = 0;
}
void Display(const pSeqlist ps)
{//打印顺序表中的元素
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
printf("%d ", ps->data[i]);
}
printf("\n");
}
void Checkcapacity(pSeqlist ps)
{
assert(ps);
if (ps->sz == ps->capacity)
{ //当sz=capacity时,说明已经没有空间可以进行插入操作,只能进行增容
Datatype* ptr = realloc(ps->data, (ps->capacity + INC)*sizeof(Datatype));
if (ptr != NULL)
{ //增容成功,将capacity置成新增容的空间大小,空间也为增容后的空间
ps->data = ptr;
ps->capacity += INC;
}
else
{ //增容失败
perror("realloc");
exit(EXIT_FAILURE);
}
}
}
void PushBack(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
assert(ps->data);
Checkcapacity(ps);//先来检测一下是否需要增容
ps->data[ps->sz] = key;
ps->sz++;
}
void PopBack(pSeqlist ps)
{
assert(ps != NULL);
if (ps->sz == 0)
{ //顺序表为空,并不需要删除
return;
}//只需将sz--,但底层该值仍存在,知识不能访问而已
ps->sz--;
}
void PushFront(pSeqlist ps, Datatype key)
{
assert(ps != NULL);
if (ps->sz == ps->capacity)
Checkcapacity(ps);
if (ps->sz < ps->capacity)
{
int i = 0;
//memmove(目标,源,字节数)
memmove(ps->data+1, ps->data,sizeof(Datatype)*(ps->sz));
/*for (i = ps->sz; i>0; i--)
{ 将从最后一个元素开始,每个元素往后挪一个
ps->data[i] = ps->data[i - 1];
}*/
ps->data[0] = key;
ps->sz++;
}
}
void PopFront(pSeqlist ps)
{
int i = 0;
assert(ps != NULL);
if (ps->sz == 0)
return;
for (i = 0; i<ps->sz-1; i++)
{ //从第二个元素开始,每个都往前挪一个
ps->data[i] = ps->data[i + 1];
}
ps->sz--;
}
int Find(pSeqlist ps, Datatype key)
{ //查找指定值
int i = 0;
assert(ps != NULL);
for (i = 0; i < ps->sz; i++)
{
if (key == ps->data[i])
return i;
}
return -1;
}
int Insert(pSeqlist ps, Datatype key, int pos)
{ //指定位置插入
int i = 0;
assert(ps != NULL);
if (ps->sz == ps->capacity)//检测是否需要增容
Checkcapacity(ps);
if (ps->sz <ps->capacity)
{ //当sz<capacity时,将pos以及pos后面的所有元素都向后挪一个
for (i = ps->sz; i >pos; i--)
{
ps->data[i] = ps->data[i-1];
} //挪完之后把要插入的值插入到pos位置
ps->data[pos] = key;
ps->sz++;
}
}
void Remove(pSeqlist ps, Datatype key)
{ //删除指定的值
int pos = 0;
assert(ps);
pos=Find(ps, key); //在顺序表中查找是否有该元素
if (pos != -1)//pos为-1就说明顺序表中不存在该元素,
{ //pos返回的是该元素所在的下标,将pos后边的元素都往前挪一个
memmove(ps->data + pos, ps->data + pos + 1, (ps->sz - pos - 1)*sizeof(Datatype));
ps->sz--;
}
}
void RemoveAll(pSeqlist ps, Datatype key)//删除所有的key
{
int pos = 0;
assert(ps);
while ((pos = Find(ps, key))!=-1)
{
Remove(ps, key);
}
}
void Swap(Datatype *a, Datatype *b)
{
Datatype tmp = *a;
*a = *b;
*b = tmp;
}
void Reverse(pSeqlist ps)
{ //逆置顺序表,即将顺序表中的元素逆置
Datatype* left = ps->data;
Datatype* right = ps->data + ps->sz - 1;
assert(ps!=NULL);
while (left < right)
{ //将最左边的和最右边的元素交换,然后座标的往后挪一个,右边的往前挪一个继续交换
Swap(left, right);
left++;
right--;
}
}
void Sort(pSeqlist ps)
{ //给顺序表中的元素进行升序排序
int i = 0;
int j = 0;
assert(ps);
for (i = 0; i < (ps->sz - 1); i++)
{ //采用冒泡排序的思想
for (j = 0; j < ps->sz-1-i; j++)
{
if (ps->data[j] > ps->data[j + 1])
{
Swap(&ps->data[j], &ps->data[j + 1]);
/*Datatype tmp = ps->data[j];
ps->data[j ] = ps->data[j+1];
ps->data[j + 1] = tmp;*/
}
}
}
}
int BinarSearch(pSeqlist ps, Datatype key)
{ //二分查找
int left = 0;
int right = ps->sz - 1;
assert(ps);
while (left <= right)
{
int mid = left + ((right - left) >> 1);
if (key == ps->data[mid])
{
return mid;
}
else if (key > ps->data[mid])
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return -1;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void test1()//尾插尾删
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 1);
//PushFront(&my_list, 2);
PushFront(&my_list, 3);
//PushFront(&my_list, 4);
PushFront(&my_list, 5);
Display(&my_list);
Insert(&my_list,2,2);
PopFront(&my_list);
Display(&my_list);
PopFront(&my_list);
Display(&my_list);
Destroy(&my_list);
}
void test2()
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 5);
PushFront(&my_list, 3);
PushFront(&my_list, 1);
Display(&my_list);
Insert(&my_list, 4, 2);
Display(&my_list);
Insert(&my_list, 2, 1);
Display(&my_list);
Destroy(&my_list);
}
void test3()
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 5);
PushFront(&my_list, 4);
PushFront(&my_list, 4);
PushFront(&my_list, 3);
PushFront(&my_list, 1);
PushFront(&my_list, 1);
Display(&my_list);
RemoveAll(&my_list, 1);
Display(&my_list);
RemoveAll(&my_list, 4);
Display(&my_list);
Destroy(&my_list);
}
void test4()
{
SeqList my_list;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 4);
PushFront(&my_list, 3);
PushFront(&my_list, 6);
PushFront(&my_list, 5);
Display(&my_list);
Sort(&my_list);
Display(&my_list);
Reverse(&my_list);
Display(&my_list);
Destroy(&my_list);
}
void test5()
{
SeqList my_list;
int pos = 0;
InitSeqList(&my_list);
PushFront(&my_list, 1);
PushFront(&my_list, 2);
PushFront(&my_list, 3);
PushFront(&my_list, 4);
PushFront(&my_list, 5);
Display(&my_list);
Sort(&my_list);
pos = BinarSearch(&my_list, 3);
printf("%d\n", pos);
pos = BinarSearch(&my_list, 6);
printf("%d\n", pos);
}
int main()
{
test5();
system("pause");
return 0;
}
好了,以上就是动态顺序表的实现。其实静态顺序表和动态顺序表的实现区别只是在插入元素时需要检测是否需要增容,需要就用realloc()进行增容。