固定大小的顺序表的结构设计
固定大小的顺序表本质是一个数组,只是封装了一下,增加了一个cursize属性
#define SEQ_INIT_SIZE 10
typedef int ElemType;
struct SeqList{
ElemType data[SEQ_INIT_SIZE];
int cursize;
};
//或者以这种形式
typedef struct SeqList{
ElemType data[SEQ_INIT_SIZE];
int cursize;
}SeqList;
int main(){
SeqList myseq;
return 0;
内部存储图
此外,由于线性表的长度可变,且所需最大存储空间随问题不同而不同,则在C语言中可用动态分配的一维数组。
可变大小的顺序表的结构设计
可变大小的顺序表定义了一个指针,初始化的时候会开辟一个空间,该空间是可以修改扩容的
#define LIST_INIT_CAPACITY 10 //数组初始化大小
#define LIST_GROW 2 //扩容倍数
typedef int ElemType;
typedef struct SeqList {
ElemType* data; //数组起始地址 .heap
int length; //数组总容量
int size; // 有效数据个数
}SeqList;
防止头文件重复引用
程序用法
//#pragma once//仅仅在这一种情况可以用,下面的具有通用性
//防止头文件被重复引用
#ifndef SEQLIST_H
#define SEQLIST_H
......
#endif
深度理解
其实“被重复引用”是指一个头文件在同一个cpp文件中被include了多次,这种错误常常是由于include嵌套造成的。
比如:存在a.h文件#include "c.h"而此时b.cpp文件导入了#include “a.h” 和#include “c.h”此时就会
造成c.h重复引用。
#pragma once是编译相关,就是说这个编译系统上能用,但在其他编译系统不一定可以,也就是说移植性差,不过现在基本上已经是每个编译器都有这个定义了。
#ifndef,#define,#endif 这个是C++语言相关,这是C++语言中的宏定义,通过宏定义避免文件
多次编译。所以在所有支持C++语言的编译器上都是有效的,如果写的程序要跨平台,最好使用这种方式。
头文件设计seqlist.h
//#pragma once
//防止头文件被重复引用
#ifndef SEQLIST_H
#define SEQLIST_H
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1 //内存溢出
#define LIST_INIT_CAPACITY 10 //数组初始化大小
#define LIST_GROW 2 //扩容倍数
typedef int Status; // 状态 TRUE FALSE
typedef int ElemType; //数组元素类型
typedef struct SeqList {
ElemType* data; //数组起始地址 .heap
int length; //数组总容量
int size; // 有效数据个数
}SeqList;
//冒泡排序
void BubbleSort(SeqList* plist);
//二分查找(前提:数组完全有序)
int BinarySearch(SeqList* plist, ElemType val);
//将两个有序顺序表合并为1个有序的顺序表
//将pla plb --> plc
void MergeList(const SeqList* pla, const SeqList* plb, SeqList* plc);
#endif
接口函数实现seqlist.cpp
#include <stdio.h>
#include <assert.h>
#include "seqlist.h"
#include <stdlib.h>
//初始化--malloc
void initSeqList(SeqList* plist) {
assert(plist != NULL); //NULL: int 0
//plist != nullptr //nullptr: (void*)0
plist->data = (ElemType*)malloc(LIST_INIT_CAPACITY*sizeof(ElemType));
if (plist->data == NULL) return;
plist->length = LIST_INIT_CAPACITY; //数组初始化容量
plist->size = 0; //有效个数
}
//销毁--data free() 释放堆内存
void DestoryList(SeqList* plist) {
assert(plist != NULL);
free(plist->data);
plist->data = NULL; // 防止野指针(悬挂指针) 如果再次free,该函数内部会检测ptr是否等于NULL,会处理防止崩溃
}
//清空 删除有效数据
void ClearList(SeqList* plist) {
assert(plist != NULL);
plist->size = 0;//在这里有一定的局限性,如果是在堆区动态申请的内存 ,需要free来释放
}
//打印数组元素
void Show(SeqList* plist) {
assert(plist != NULL);
int n = plist->size;
for (int i = 0; i < n; i++) {
printf("%5d",plist->data[i]);
}
printf("\n");
}
//扩容操作 -- 写对 写好(效率,边界(鲁棒性))
Status Grow(SeqList* plist) {
assert(plist != NULL);
if (plist == NULL) return ERROR;
int newlength = plist->length * LIST_GROW;
ElemType* temp = (ElemType*)realloc(plist->data,newlength*sizeof(ElemType));
if (temp == NULL) { return OVERFLOW; }
plist->data = temp;
plist->length = newlength;
return OK;
}
//判满操作
Status IsFull(SeqList* plist) {
assert(plist != NULL); // null-> null. 崩
return plist->size == plist->length;
}
//头插
Status InsertHead(SeqList* plist, ElemType val) {
assert(plist != NULL);
if (IsFull(plist) && Grow(plist) != OK) {
return OVERFLOW;
}
for (int i = plist->size - 1; i >= 0; i--) {
plist->data[i + 1] = plist->data[i];
}
plist->data[0] = val;
plist->size++;
return OK;
}
//尾插
Status InsertTail(SeqList* plist, ElemType val) {
assert(plist != NULL);
if (IsFull(plist) && Grow(plist) != OK) {
return OVERFLOW;
}
plist->data[plist->size] = val;
plist->size++;
return OK;
}
//指定位置插入 pos -- 下标
Status InsertPosVal(SeqList* plist, int posindex, ElemType val) {
assert(plist != NULL);
if (posindex < 0 || posindex > plist->size) {
return ERROR;
}
if (IsFull(plist) && Grow(plist) != OK) {
return OVERFLOW;
}
//从pos后续数据向后移动
for (int i = plist->size - 1; i >= posindex; i--) {
plist->data[i + 1] = plist->data[i];
}
plist->data[posindex] = val;
plist->size++;
return OK;
}
//判空操作
Status IsEmpty(SeqList* plist) {
assert(plist != NULL);
return plist->size == 0;
}
//头删
Status DeleteHead(SeqList* plist) {
return DeletePos(plist,0);
}
//尾删 [1][3][] size:1
Status DeleteTail(SeqList* plist) {
return DeletePos(plist,plist->size-1);
}
//指定位置删除
Status DeletePos(SeqList* plist, int posindex) {
assert(plist != NULL);
if (IsEmpty(plist) || posindex < 0 || posindex >= plist->size) return FALSE;
//向前移动 覆盖前一个
for (int i = posindex; i < plist->size; i++) {
plist->data[i] = plist->data[i+1];
}
plist->size--;
return OK;
}
//删除指定的元素 1 2 2 2 2 -> 2 剩余1
Status DeleteVal(SeqList* plist, ElemType val) {
assert(plist != NULL);
int index;
while ((index = SearchVal(plist, val)) >= 0) {
DeletePos(plist,index);
}
return OK;
}
//查询某个元素返回下标
int SearchVal(SeqList* plist, ElemType val) {
assert(plist != NULL);
int index = -1;
for (int i = 0; i < plist->size; i++) {
if (plist->data[i] == val) {
index = i;
break;
}
}
return index;
}
//冒泡排序
void BubbleSort(SeqList* plist) {
int len = plist->size;
bool flag;
for (int i = len-1; i>=0; i--) {
flag = false;
for (int j = 0; j < i; j++) {
if (plist->data[j + 1] < plist->data[j]) {
ElemType temp = plist->data[j + 1];
plist->data[j + 1] = plist->data[j];
plist->data[j] = temp;
flag = true;
}
}
if (!flag) {
break;
}
}
}
//二分查找(前提:数组完全有序) -- 非递归
//时间复杂度O(logN)
//空间复杂度O(1)
int BinarySearch(SeqList* plist, ElemType val) {
//BubbleSort(plist);
int len = plist->size;
int i = 0, j = len - 1;
while (i <= j) {
int mid = i + (j - i) / 2;
if (plist->data[mid] == val)return mid;
else if (plist->data[mid] > val)j = mid - 1;
else i = mid + 1;
}
return -1;
}
int SearchSection(SeqList* plist, int left, int right, ElemType val) {
if (left > right)return -1;
int mid = (left + right) / 2;
if (plist->data[mid])return mid;
if (plist->data[mid] > val) {
return SearchSection(plist, left, mid - 1, val);
}
else {
return SearchSection(plist, mid+1,right, val);
}
}
//二分查找(前提:数组完全有序) -- 递归(自己调自己,退出条件,问题规模)
//时间复杂度O(logN)
//空间复杂度O(logN)
int BinarySearch(SeqList* plist, ElemType val) {
assert(plist != nullptr);
SearchSection(plist, 0, plist->size, val);
}
//将两个有序顺序表合并为1个有序的顺序表
//将pla plb --> plc
void MergeList(const SeqList* pla, const SeqList* plb, SeqList* plc) {
assert(pla != nullptr && plb != nullptr && plc != nullptr);
int i = 0, j = 0, z = 0;
while(i < pla->size&& j < plb->size) {
if (pla->data[i] < plb->data[j]) {
//plc->data[z++] = pla->data[i++];
InsertTail(plc, pla->data[i++]);
}
else {
//plc->data[z++] = plb->data[j++];
InsertTail(plc, plb->data[j++]);
}
}
if (i >= pla->size) {
while (j<plb->size) {
//plc->data[z++] = plb->data[j++];
InsertTail(plc, plb->data[j++]);
}
}
if (i >= pla->size) {
while (j < plb->size) {
//plc->data[z++] = pla->data[i++];
InsertTail(plc, pla->data[i++]);
}
}
}