1. 程式人生 > >靜態順序表的實現

靜態順序表的實現

順序表:用一段地址連續的儲存地址單元一次儲存資料元素的線性結構。

實現一個具有增、刪、查、改、初始化、輸入、列印等簡單功能的順序表。

實現程式碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int DataType;

#define MAX_SIZE (100)

typedef struct SeqList{
	DataType array[MAX_SIZE];
	int size;   // 1. 儲存順序表裡已經存了的資料個數
	// 2. 當前可用下標
}	SeqList;

//typedef struct SeqList SeqList

// 介面(函式)
// 初始化/銷燬
// 增/刪/查/改(寫)

//初始化(函式設計)
void SeqListInit(SeqList *pSeq)
{
	//1.初始化 size
	//2.可能需要去把容器空間清空下

	assert(pSeq != NULL);
	pSeq->size = 0;
	//memset(pSeq->array, 0, MAX_SIZE * sizeof(DataType));
}

//銷燬
void SeqListDestroy(SeqList *pSeq)
{
	assert(pSeq);
	pSeq->size = 0;
}

//增
//尾插(儘量和 C++ 的 STL 統一)
void SeqListPushBack(SeqList *pSeq, DataType data)
{
	assert(pSeq);

	//特殊情況(滿了)
	if (pSeq->size >= MAX_SIZE){
		printf("滿了!\n");
		assert(0);
		return;
	}

	//正常情況
	pSeq->array[pSeq->size] = data;
	pSeq->size++;
}

//頭插
void SeqListPushFront(SeqList *pSeq, DataType data)
{
	assert(pSeq);

	//特殊情況(滿了)
	if (pSeq->size >= MAX_SIZE){
		printf("滿了!\n");
		assert(0);
		return;
	}

	//正常情況
	//現有資料整體往後搬一格
	for (int i = pSeq->size; i > 0; i--) {
		// 前面是位置  後面是資料
		pSeq->array[i] = pSeq->array[i - 1];
	}

	// i 代表的是資料
	/*
	for (int i = pSeq->size - 1; i >= 0; i--) {
	pSeq->array[i + 1] = pSeq->array[i];
	}
	*/

	//插入
	pSeq->array[0] = data;
	pSeq->size++;
}

//中間插入
void SeqListInsert(SeqList *pSeq, int pos, DataType data)
{
	assert(pSeq);
	assert(pos >= 0 && pos <= pSeq->size);

	//特殊情況(滿了)
	if (pSeq->size >= MAX_SIZE){
		printf("滿了!\n");
		assert(0);
		return;
	}

	//正常情況
	// 1. 資料搬移
	// 1) 從後往前 2) i 取 資料 [size - 1, pos]
	for (int i = pSeq->size - 1; i >= pos; i--){
		pSeq->array[i + 1] = pSeq->array[i];
	}

	// 2. 插入
	pSeq->array[pos] = data;
	pSeq->size++;
}

//刪
//尾刪
void SeqListPopBack(SeqList *pSeq)
{
	assert(pSeq);

	//特殊情況(空了)
	if (pSeq->size <= 0){
		printf("空了!\n");
		assert(0);
		return;
	}

	//正常情況
	pSeq->size--;
}

//頭刪
void SeqListPopFront(SeqList *pSeq)
{
	assert(pSeq);

	//特殊情況(空了)
	if (pSeq->size <= 0){
		printf("空了\n");
		assert(0);
		return;
	}

	//通常情況
	for (int i = 0; i < pSeq->size; i++){
		pSeq->array[i] = pSeq->array[i + 1];
	}

	pSeq->size--;
}

//中間刪
void SeqListErase(SeqList *pSeq, int pos)
{
	assert(pSeq);
	assert(pos >= 0 && pos < pSeq->size);

	// 特殊情況(空了)
	if (pSeq->size <= 0){
		printf("空了!\n");
		assert(0);
		return;
	}

	// 資料搬移
	// 1) 從前往後 2) i 取位置
	for (int i = pos; i <= pSeq->size - 2; i++){
		pSeq->array[i] = pSeq->array[i + 1];
	}

	pSeq->size--;
}

//列印
// 傳指標減少空間,不改變值
void SeqListPrint(const SeqList *pSeq)
{
	assert(pSeq != NULL);

	for (int i = 0; i < pSeq->size; i++){
		printf("%d  ", pSeq->array[i]);
	}
	printf("\n");
}



// 查詢
// 找到第一個遇到的數的下標,沒找到返回 -1 (更理想返回型別 ssize_t)
int SeqListFind(SeqList *pSeq, DataType data)
{
	// 特殊情況(空)
	if (pSeq->size <= 0) {
		printf("空\n");
		assert(0);
		return -1;
	}

	//順序遍歷查詢
	for(int i = 0; i < pSeq->size; i++){
		if (data == pSeq->array[i]){
			//返回下標
			return i;
		}
	}

	//沒找到
	return -1;
}

// 查詢(方法2)
int SeqListFind2(SeqList *pSeq, DataType data)
{
	// 特殊情況(空)
	if (pSeq->size <= 0) {
		printf("空\n");
		assert(0);
		return -1;
	}

	//二分查詢(前提:有序)
	int left = 0;
	int right = pSeq->size;
	int mid = 0;
	while (right>=left){
		mid = (left + right) / 2;
		if (data == pSeq->array[mid]) {
			// 找到返回下標
			return mid;
		}
		else if (data > pSeq->array[mid]){
			left = mid + 1;
		}
		else{
			right = mid - 1;
		}
	}

	//沒找到
	if (right < left){
		return -1;
	}
}

// 刪除第二種形態 (根據資料刪除)
// 1. 刪遇到的第一個資料
void SeqListRemove(SeqList *pSeq, DataType data)
{
	int pos = SeqListFind(pSeq, data);
	if (pos == -1){
		//沒找到
		return;
	}

	SeqListErase(pSeq, pos);
}

//2.刪遇到的所有資料
//(1).
void SeqListRemoveAll1(SeqList *pSeq, DataType data)
{
	int pos = 0;
	while ((pos = SeqListFind(pSeq, data)) != -1){
		SeqListErase(pSeq, pos);
	}
}

// (2). 一次遍歷刪除
// 好處: 一次遍歷,時間比較快
// 壞處: 開了新空間,空間大小和 size 有關係
// 1) 開新陣列
void SeqListRemoveAll2(SeqList *pSeq, DataType data)
{
	DataType *newArray = (DataType*)malloc(sizeof(DataType)*pSeq->size);
	int i, j;
	for (i = 0, j = 0; i < pSeq->size; i++){
		if (data != pSeq->array[i]){
			newArray[j] = pSeq->array[i];
			j++;
		}
	}

	//把資料搬回來
	for (i = 0; i < j; i++){
		pSeq->array[i] = newArray[i];
	}
	pSeq->size = j;

	//釋放
	free(newArray);
}

void SeqListRemoveAll3(SeqList *pSeq, DataType data)
{
	int i, j;
	for (i = 0, j = 0; i < pSeq->size; i++){
		if (data != pSeq->array[i]){
			pSeq->array[j] = pSeq->array[i];
			j++;
		}
	}
	pSeq->size = j;
}

測試:

// 使用場景
void test()
{
	// 1.
	SeqList seqList;
	SeqListInit(&seqList);	// 1. seqList, 2. &seqList	// 1). 指標空間更小 2).改變值 

	// 2.
	//SeqList *pSeqList;
	//pSeqList = SeqListInit();

	printf("插入:\n");
	SeqListPushBack(&seqList, 6);
	SeqListPushBack(&seqList, 7);
	SeqListPushBack(&seqList, 8);
	SeqListPushBack(&seqList, 9);
	SeqListPrint(&seqList);

	printf("尾插:\n");
	SeqListPopBack(&seqList);
	SeqListPrint(&seqList);

	printf("頭插:\n");
	SeqListPushFront(&seqList, 4);
	SeqListPushFront(&seqList, 3);
	SeqListPushFront(&seqList, 2);
	SeqListPushFront(&seqList, 1);
	SeqListPrint(&seqList);

	printf("中間插:\n");
	SeqListInsert(&seqList, 4, 5);
	SeqListPrint(&seqList);

	printf("尾刪:\n");
	SeqListPopBack(&seqList);
	SeqListPrint(&seqList);

	printf("頭刪:\n");
	SeqListPopFront(&seqList);
	SeqListPrint(&seqList);

	printf("中間刪:\n");
	SeqListErase(&seqList, 5);
	SeqListPrint(&seqList);

	printf("查詢:\n");
	printf("%d\n", SeqListFind(&seqList, 5));
	printf("%d\n", SeqListFind2(&seqList, 5));
	
	printf("根據資料刪除:\n");
	SeqListRemoveAll1(&seqList,2);
	SeqListPrint(&seqList);

	SeqListRemoveAll2(&seqList, 3);
	SeqListPrint(&seqList);

	SeqListRemoveAll3(&seqList, 4);
	SeqListPrint(&seqList);
}

主函式:

int main()
{
	test();
	return 0;
}

效果: