顺序表的实现

Posted peiyao456

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了顺序表的实现相关的知识,希望对你有一定的参考价值。

一直对顺序表的概念不是很清楚,终于在一次的学习中,明白了以下(红色标注):

        线性表是一种最简单、最基础的数据结构,线性表中的元素都是一对一的,除了第

个元素和最后一个元素之外,其他元素都是首尾相接。通俗地讲,线性表中的元素都

是连在一条线中的,不管是直线还是曲线。如果是直线,我们称这个线性表为顺序表;

如果是曲线,我们称其为链表。

本篇文章,我来主要整理出关于顺序表的内容。在通讯录的多版本实现这篇博客中,我们

 知道,根据顺序表的容量大小是否固定可将顺序表分为静态顺序表和动态顺序表。

对于有好的变成习惯的程序员来说,使用assert是比较多的,可是,并不是所有的指针都

可以用assert来断言,下边我来具体说一下,希望对那些不太会用断言的人有一点帮助~~

assert的正确使用:

assert是一个宏,原型定义在头文件assert.h中,在vs2015编译器下给出的定义如下图:


在执行assert宏时,它会先计算出表达式expression的值,如果值为假,那么它想stderr

打印出一条出错信息,通过调用abort来终止程序执行。

细心的你有可能会发现expression的前边怎么会有两个‘!’呢。是不是多余的呢??其实

并不是。如果expression不是0,!!expression = =1,否则,!!expression = =0,这下你就

知道了吧。为什么要这样做呢??这里用到了逻辑运算符'||'的短路功能。如果expression是真,后边的不执行,如果是假,打印出出错信息~~这个简直是妙~

看着assert好像是使用越多越好,其实并非这样。频繁的调用assert会极大地影响程序的

性能,增加额外开销。并且它只能用在debug版本,release版本并不可。

在程序结束后,可以通过在包含#include<assert.h>的语句之前插入#define NDEBUG来

禁用assert调用,比如(只给出头文件):

#include<stdio.h>

#define NDEBUG

#include<assert.h>

assert的用法总结:

(1)在函数开始处检验传入参入的合法性。这个我们平时使用的比较多。可是,如果

某个条件在为假时,对于程序 而言仍为合法值,此时就不要assert断言了。(关于这

个,在链表的博客中再述)

(2)每个assert最好只检验一个条件。否则,如果断言失败,我们无法直观的判断哪个

条件失败。

(3)assert里的参数不能使用改变环境的语句。比如:

assert(i++<100);这条语句是不正确的,这是因为如果在这条语句执行之前i=100,i++

<100这个条件为假,程序直接报错,i++就不会执行。

(4)有的地方,assert不能代替条件过滤。这里我举不出例子,有见解的朋友,可以在

博客下边的评论栏指出。

由于通讯录版本已经对静态顺序表做了解释,这里只给出代码和编码过程中的注意事项

//SeqList.c
#include"SeqList.h"
void menu()
{
	printf("*******1.初始化顺序表*******\\n");
	printf("*******2.显示出顺序表*******\\n");
	printf("*******3.顺序表尾插*********\\n");
	printf("*******4.顺序表尾删*********\\n");
	printf("*******5.顺序表头插*********\\n");
	printf("*******6.顺序表头删*********\\n");
	printf("*******7.插入元素***********\\n");
	printf("*******8.删除给定元素*******\\n");
	printf("*******9.删除给定元素的全部**\\n");
	printf("*******10.顺序表排序*********\\n");
	printf("*******11.折半查找元素*******\\n");
	printf("*******0.退出****************\\n");
}
//初始化
void InitSeq(pSeqList  pSeq)
{
	assert(pSeq);
	pSeq->sz = 0;
	memset(pSeq,0,sizeof(TypeName) * MAX);
	printf("初始化成功!\\n");
}
//打印
void PrintSeq(pSeqList  pSeq)
{
	assert(pSeq);
	int i = 0;
	printf("顺序表中的元素有:\\n");
	for (i = 0;i < pSeq->sz;i++)
	{
		printf("%d ",pSeq->Data[i]);
	}
	printf("\\n");
}
//尾插
void PushBack(pSeqList  pSeq, TypeName x)
{
	assert(pSeq);
	if (pSeq->sz == MAX)
	{
		printf("顺序表已满,不可插入");
		exit(EXIT_FAILURE);
	}
	pSeq->Data[pSeq->sz] = x;
	pSeq->sz++;
	printf("尾插成功!\\n");
}
//尾删
void PopBack(pSeqList  pSeq)
{
	assert(pSeq);
	if (pSeq->sz == 0)
	{
		printf("顺序表已空,不可删除");
		exit(EXIT_FAILURE);
	}
	pSeq->sz--;
	printf("尾删成功!\\n");
}
//插入
void Insert(pSeqList  pSeq, int pos, TypeName x)
{
	assert(pSeq);
	int i = 0;
	if (pSeq->sz == MAX || pos == MAX)
	{
		printf("顺序表已满或者插入位置不合理\\n");
		exit(EXIT_FAILURE);
	}
	for (i = pSeq->sz - 1;i >= pos; i--)
	{
		pSeq->Data[i + 1] = pSeq->Data[i];
	}
	pSeq->Data[pos] = x;
	pSeq->sz++;
	printf("插入成功!\\n");
}
//删除给定元素
void Remove(pSeqList  pSeq, TypeName x)
{
	assert(pSeq);
	if (pSeq->sz == 0)
	{
		printf("顺序表已空,不可删除");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	for (i = 0;i < pSeq->sz;i++)
	{
		if (pSeq->Data[i] == x)
			break;
	}
	if (i == pSeq->sz)
	{
		printf("要删除的元素不存在\\n");
		exit(EXIT_FAILURE);
	}
	for (j = i + 1;j < pSeq->sz;j++)
	{
		pSeq->Data[j-1] = pSeq->Data[j];
	}
	pSeq->sz--;
	printf("删除成功!\\n");
}
//删除给定元素的所有
void RemoveAll(pSeqList  pSeq, TypeName x)
{
	assert(pSeq);
	int count = 0;
	if (pSeq->sz == 0)
	{
		printf("顺序表已空,不可删除");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = pSeq->sz-1;
	while(i < pSeq->sz)
	{
		if (pSeq->Data[i] == x )
		{
			while (pSeq->Data[j] == x)
			{
				j--;
			}
			pSeq->Data[i] = pSeq->Data[j];
			count++;
			
		}
		i++;
	}
	pSeq->sz -= count;
	printf("删除成功!\\n");
}
//头插
void PushFront(pSeqList  pSeq, TypeName x)
{
	assert(pSeq);
	int i = 0;
	if (pSeq->sz == MAX)
	{
		printf("顺序表已满,不可插入");
		exit(EXIT_FAILURE);
	}
	for (i = pSeq->sz - 1;i >= 0;i--)
	{
		pSeq->Data[i + 1] = pSeq->Data[i];
	}
	pSeq->Data[0] = x;
	pSeq->sz++;
	printf("头插成功!\\n");
}
//头删
void PopFront(pSeqList  pSeq)
{
	assert(pSeq);
	int i = 0;
	if (pSeq->sz == 0)
	{
		printf("顺序表已空,不可删除");
		exit(EXIT_FAILURE);
	}
	for (i = 1;i < pSeq->sz ;i++)
	{
		pSeq->Data[i - 1] = pSeq->Data[i];
	}
	pSeq->sz--;
	printf("头删成功!\\n");
}
//排序
void Sort(pSeqList  pSeq)
{
	assert(pSeq);
	int i = 0;
	int j = 0;
	int flag = 0;
	TypeName tmp= 0;
	if (pSeq->sz == 0)
	{
		printf("顺序表已空,不可排序");
		exit(EXIT_FAILURE);
	}
	for (i = 0;i < pSeq->sz;i++)
	{
		flag = 1;
		for (j = 0;j < pSeq->sz - i - 1;j++)
		{
			if (pSeq->Data[j] > pSeq->Data[j + 1])
			{
				tmp = pSeq->Data[j];
				pSeq->Data[j] = pSeq->Data[j + 1];
				pSeq->Data[j + 1] = tmp;
				flag = 0;
			}
		}
		if (flag == 1)
			break;
	}
	//printf("排序成功!\\n");
}
//折半查找
void BinarySearch(pSeqList  pSeq, TypeName x)
{
	assert(pSeq);
	int left = 0;
	int right = pSeq->sz - 1;;
	int middle = 0;
	if (pSeq->sz == 0)
	{
		printf("顺序表已空,不可查找");
		exit(EXIT_FAILURE);
	}
	Sort(pSeq);
	while (left <= right)
	{
		middle = (left + right)/2;
		if (pSeq->Data[middle] == x)
		{
			printf("查找成功!\\n");
			return;
		}
		else if (pSeq->Data[middle] < x)
		{
			left = middle + 1;
		}
		else
		{
			right = middle - 1;
		}
	}
	printf("要查找的元素不存在!\\n");
}
//SeqList.h
#ifndef __SEQLIST_H__
#define  __SEQLIST_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<memory.h>
#include<windows.h>
#define MAX 100
typedef int TypeName;
typedef struct SeqList
{
	TypeName Data[MAX];
	int sz;
}SeqList,*pSeqList;
enum op
{
	EXIT,
	INIT,
	PRINT,
	PUSHBACK,
	POPBACK,
	PUSHFRONT,
	POPFRONT,
	INSERT,
	REMOVE,
	REMOVEALL,
	SORT,
	BINARYSEARCH
};

void InitSeq(pSeqList  pSeq);
void PrintSeq(pSeqList  pSeq);
void PushBack(pSeqList  pSeq, TypeName x);
void PopBack(pSeqList  pSeq);
void PushFront(pSeqList  pSeq, TypeName x);
void PopFront(pSeqList  pSeq);
void Insert(pSeqList  pSeq,TypeName pos,TypeName x);//在给定位置插入给定元素
void Remove(pSeqList  pSeq,TypeName x);//删除表中的特定元素
void RemoveAll(pSeqList  pSeq,TypeName x);//删除表中所有值为x的元素
void Sort(pSeqList  pSeq);
void BinarySearch(pSeqList  pSeq,TypeName x);


#endif //__SEQLIST_H__
//test.c
#include"SeqList.h"
void test()
{
	SeqList seq;
	//pSeqList pseq = &seq;
	int pos = 0;
	int input = 1;
	TypeName x = 0;
	while (input)
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			break;
		case INIT:
			InitSeq(&seq);
			break;
		case PRINT:
			PrintSeq(&seq);
			break;
		case INSERT:
			printf("请输入插入元素的位置:>");
			scanf("%d",&pos);
			printf("请输入插入元素的值:>");
			scanf("%d", &x);
			Insert(&seq, pos, x);
			break;
		case PUSHBACK:
			printf("请输入插入元素的值:>");
			scanf("%d", &x);
			PushBack(&seq,x);
			break;
		case POPBACK:
			PopBack(&seq);
			break;
		case PUSHFRONT:
			printf("请输入插入元素的值:>");
			scanf("%d", &x);
			PushFront(&seq,x);
			break;
		case POPFRONT:
			PopFront(&seq);
			break;
		case SORT:
			Sort(&seq);
			break;
		case BINARYSEARCH:
			printf("请输入查找元素的值:>");
			scanf("%d", &x);
			BinarySearch(&seq, x);
			break;
		case REMOVE:
			printf("请输入要删除的元素:>");
			scanf("%d", &x);
			Remove(&seq, x);
			break;
		case REMOVEALL:
			printf("请输入要删除的元素:>");
			scanf("%d", &x);
			RemoveAll(&seq, x);
			break;
		}
	}
}
int main()
{
	test();
	system("pause");
	return 0;
}

静态顺序表编码的注意:

(1)删除之前必须对顺序表是否为空进行检查,如果为空不可删除。

(2)插入之前必须对顺序表是否满进行检查,如果已满,不可插入。

(3)折半查找之前必须对元素排序。(这个属于两个版本共同需要注意的)

下边给出动态顺序表的实现代码:

//SeqList.h
#ifndef __SEQLIST_H__
#define __SEQLIST_H__
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
enum OP
{
	EXIT,
	PRINT,
	PUSHBACK,
	POPBACK,
	PUSHFRONT,
	POPFRONT,
	REMOVE,
	REMOVEALL,
	BOTTLESORT,
	INSERTSORT,
	SELECTSORT,
	BINARYSEARCH,
	ERASE
};
#define DEFAULT_SIZE 3
typedef int DataType;
typedef struct Seqlist
{
	DataType *data;
	int size;
	int capacity;
}SeqList,*pSeqList;
void InitSeqList(pSeqList pSeq);
void DestroySeqList(pSeqList pSeq);
void PushBack(pSeqList pSeq,DataType x);
void PopBack(pSeqList pSeq);
void PushFront(pSeqList pSeq,  DataType x);
void PopFront(pSeqList pSeq);
void Remove(pSeqList pSeq, DataType x);
void RemoveAll(pSeqList pSeq, DataType x);
void BubbleSort(pSeqList pSeq);
void InsertSort(pSeqList pSeq);
void SelectSort(pSeqList pSeq);
void BinarySearch(pSeqList pSeq);
void Erase(pSeqList pSeq,int pos);
void PrintSeqList(pSeqList pSeq);
#endif// __SEQLIST_H__
//SeqList.c
#include"SeqList.h"

void check_capacity(pSeqList pSeq)
{
	assert(pSeq);
	if (pSeq->capacity == pSeq->size)
	{
		DataType *tmp = (DataType *)realloc(pSeq->data,(pSeq->capacity +DEFAULT_SIZE)*sizeof(DataType));
		if (NULL == tmp)
		{
			printf("out of memory.");
			exit(EXIT_FAILURE);
		}
		else
		{
			pSeq->data = tmp;
			pSeq->capacity += DEFAULT_SIZE;
		}
	}
}
void InitSeqList(pSeqList pSeq)
{
	assert(pSeq);
	pSeq->data = (DataType*)malloc(2*sizeof(DataType));
	if (NULL == pSeq->data)
	{
		printf("out of memory\\n");
		exit(EXIT_FAILURE);
	}
	pSeq->size = 0;
	pSeq->capacity = 2;
}
void DestroySeqList(pSeqList pSeq)
{
	assert(pSeq);
	free(pSeq->data);
	pSeq->size = 0;
	pSeq->capacity = 0;
	pSeq->data = NULL;
}
void PushBack(pSeqList pSeq, DataType x)
{
	assert(pSeq);
	check_capacity(pSeq);
	pSeq->data[pSeq->size] = x;
	pSeq->size++;
	printf("尾插成功!\\n");
}
void PopBack(pSeqList pSeq)
{
	assert(pSeq);
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	pSeq->size--;
	printf("尾删成功!\\n");
}
void PushFront(pSeqList pSeq, DataType x)
{
	assert(pSeq);
	check_capacity(pSeq);
	int i = 0;
	for (i = pSeq->size - 1;i >= 0;i--)
	{
		pSeq->data[i + 1] = pSeq->data[i];
	}
	pSeq->data[0] = x;
	pSeq->size++;
	printf("头插成功!\\n");
}
void PopFront(pSeqList pSeq)
{
	assert(pSeq);
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	for (i = 1;i < pSeq->size - 1;i++)
	{
		pSeq->data[i - 1] = pSeq->data[i];
	}
	pSeq->size--;
	printf("头删成功!\\n");
}
void Remove(pSeqList pSeq, DataType x)
{
	assert(pSeq);
	int i = 0;
	int j = 0;
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	for (i = 0;i < pSeq->size;i++)
	{
		if (x == pSeq->data[i])
			break;
	}
	for (j = i + 1;j < pSeq->size;j++)
	{
		pSeq->data[j - 1] = pSeq->data[j];
	}
	pSeq->size--;
	printf("删除指定元素成功!\\n");
}
void RemoveAll(pSeqList pSeq, DataType x)
{
	assert(pSeq);
	int i = 0;
	int count = 0;
	int j = 0;
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	/*for (i = 0;i < pSeq->size;i++)
	{
		if (pSeq->data[i] == x)
		{
			count++;
		}
	}*/
	i = 0;
	j = pSeq->size - 1;
	/*while (j >= pSeq->size - count && i < pSeq->size - count)
	{
		if (pSeq->data[j] != x && pSeq->data[i] == x)
		{
			pSeq->data[i] = pSeq->data[j];
		}
		j--;
		i++;
	}*/
	while (i < pSeq->size)
	{
		if (pSeq->data[i] == x)
		{
			while (pSeq->data[j] == x)
			{
				j--;
			}
			pSeq->data[i] = pSeq->data[j];
			count++;
		}
		i++;
	}
	pSeq->size -= count;
	printf("delete success!\\n");
}
void BubbleSort(pSeqList pSeq)
{
	assert(pSeq);
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	int k = pSeq->size - 1;
	int tmp = 0;
	int m = 0;
	int flag = 0;
	for (i = 0;i < pSeq->size - 1;i++)
	{
		flag = 1;
		for (j = 0;j < k;j++)
		{
			if (pSeq->data[j]>pSeq->data[j + 1])
			{
				tmp = pSeq->data[j];
				pSeq->data[j] = pSeq->data[j + 1];
				pSeq->data[j + 1] = tmp;
				m = j;//m is used for recording the position of last swap
				flag = 0;
			}
		}
		k = m;
		if (flag == 1)
		{
			break;
		}
	}
	printf("successful bottlesort\\n");
}
void InsertSort(pSeqList pSeq)
{
	assert(pSeq);
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	int tmp = 0;
	for (i = 1;i < pSeq->size;i++)
	{
		tmp = pSeq->data[i];
		for (j = i - 1;j >= 0 && pSeq->data[j] > tmp;j--)
		{
			pSeq->data[j + 1] = pSeq->data[j];
		}
		pSeq->data[j + 1] = tmp;
	}
	printf("successful insertsort\\n");
}
void SelectSort(pSeqList pSeq)
{
	assert(pSeq);
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	int min = 0;//the index of min number
	int tmp = 0;
	for (i = 0;i < pSeq->size;i++)
	{
		min = i;
		for (j = i;j < pSeq->size;j++)
		{
			if (pSeq->data[j] < pSeq->data[min])
			{
				min = j;
			}
		}
		if (min != i)
		{
			tmp = pSeq->data[i];
			pSeq->data[i] = pSeq->data[min];
			pSeq->data[min] = tmp;
		}
	}
	printf("successful selectsort\\n");
}
void BinarySearch(pSeqList pSeq, DataType x)
{
	assert(pSeq);
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	SelectSort(pSeq);//before searching,we must sort seqlist
	int left = 0;
	int right = pSeq->size - 1;
	int middle = 0;
	while (left < right)
	{
		middle = (left + right) / 2;
		if (x == pSeq->data[middle])
		{
			printf("have found\\n");
			return;
		}
		else if (x < pSeq->data[middle])
		{
			right = middle - 1;
		}
		else
		{
			left = middle + 1;
		}
	}
	printf("not found\\n");
}
void Erase(pSeqList pSeq, int pos)
{
	assert(pSeq);
	if (0 == pSeq->size)
	{
		printf("seqlist is empty.\\n");
		exit(EXIT_FAILURE);
	}
	pSeq->data[pos] = pSeq->data[pSeq->size - 1];
	pSeq->size--;
	printf("successful delete designated position\\n");
}
void PrintSeqList(pSeqList pSeq)
{
	assert(pSeq);
	int i = 0;
	printf("动态顺序表中的元素为:\\n");
	for (i = 0;i < pSeq->size;i++)
	{
		printf("%d ",pSeq->data[i]);
	}
	printf("\\n");
}
//test.c
#include"SeqList.h"
void menu()
{
	printf("-------动态顺序表管理系统-------\\n");
	printf("-------0.退出-------------------\\n");
	printf("-------1.显示-------------------\\n");
	printf("-------2.尾插-------------------\\n");
	printf("-------3.尾删-------------------\\n");
	printf("-------4.头插-------------------\\n");
	printf("-------5.头删-------------------\\n");
	printf("-------6.删除指定---------------\\n");
	printf("-------7.删除指定全部-----------\\n");
	printf("-------8.冒泡排序---------------\\n");
	printf("-------9.插入排序---------------\\n");
	printf("-------10.选择排序--------------\\n");
	printf("-------11.折半查找---------------\\n");
	printf("-------12.删除指定位置-----------\\n");
}
void test()
{
	SeqList seq;
	pSeqList pSeq = &seq;
	DataType x = 0;
	int input = 1;
	int pos = 0;
	InitSeqList(pSeq);
	while (input)
	{
		menu();
		printf("请选择:>");
		scanf("%d",&input);
		switch (input)
		{
		case EXIT:
			DestroySeqList(pSeq);
			break;
		case PRINT:
			PrintSeqList(pSeq);
			break;
		case PUSHBACK:
			printf("请输入要插入的元素:\\n");
			scanf("%d",&x);
			PushBack(pSeq,x);
			break;
		case POPBACK:
			PopBack(pSeq);
			break;
		case PUSHFRONT:
			printf("请输入要插入的元素:\\n");
			scanf("%d", &x);
			PushFront(pSeq,x);
			break;
		case POPFRONT:
			PopFront(pSeq);
			break;
		case BOTTLESORT:
			BubbleSort(pSeq);
			break;
		case SELECTSORT:
			SelectSort(pSeq);
			break;
		case INSERTSORT:
			InsertSort(pSeq);
			break;
		case ERASE:
			printf("请输入要删除元素的位置:\\n");
			scanf("%d", &pos);
			Erase(pSeq, pos);
			break;
		case BINARYSEARCH:
			printf("请输入要查找的元素:\\n");
			scanf("%d", &x);
			BinarySearch(pSeq, x);
			break;
		case REMOVE:
			printf("请输入要删除的元素:\\n");
			scanf("%d", &x);
			Remove(pSeq, x);
			break;
		case REMOVEALL:
			printf("请输入要删除的元素:\\n");
			scanf("%d", &x);
			RemoveAll(pSeq, x);
			break;
		}
	}
}
int main()
{
	test();
	system("pause");
	return 0;
}

动态顺序表的注意事项:

(1)插入之前对顺序表的大小与顺序表容量之间的关系进行判断,如果相等,扩容。

(2)删除、排序等操作之前需要对顺序表是否为空进行判断。

在最近经常碰到以下错误:(如图)


读取位置发生冲突,这是因为没有对某些数据进行初始化导致错误,以上错误就是未调

用初始化函数导致。

有时,程序运行着运行着,就会突然崩,弹出一个窗口,某处触发了一个断点,这是因

为这个地方的函数参数搞错导致吧。

如果是提示某处写入异常,可能是对常量赋值导致吧。

以上内容如有问题,请指出~~


以上是关于顺序表的实现的主要内容,如果未能解决你的问题,请参考以下文章

顺序表详解及其c语言代码实现

C数据结构单链表接口函数逻辑解析与代码实现(含详细代码注释)

Java数据结构:快速了解顺序表以及实现

顺序表的java实现

Java数据结构(线性表)--线性表的顺序存储及其实现

线性表的链式存储(C代码实现)