数据结构—顺序表的基本操作

一、线性表

线性表是最常用且简单的一种数据结构。简言之,一个线性表是n个数据元素的有限序列。至于每个数据元素的具体含义,在不同的情况下各不相同,它可以是一个整数或一个字符,也可以是一页书,甚至其他更复杂的信息。
线性表按其数据的存储方式分为两种:

  • 顺序表:数据结点之间,逻辑相邻,物理也相邻;
  • 链表:数据结点之间,逻辑相邻,物理不一定相邻。

二、顺序表

2-1 结构设计

固定大小的顺序表的结构设计

#define SEQ_INIT_SIZE 10
typedef int ElemType;//数组元素类型

typedef struct SeqList {
	ElemType data[SEQ_INIT_SIZE];//固定大小的连续存储空间
	int size;//当前有效元素个数
}SeqList;

可变大小的顺序表的结构设计

typedef int ElemType;//数组元素类型
typedef struct SeqList {
	ElemType* data;//数组起始地址
	int length;    //数组总容量
	int size;      //有效数据个数
}SeqList;

2-2 函数实现接口声明

//1.初始化
void initSeqList(SeqList* plist);
//2.销毁   free
void DestoryList(SeqList* plist);
//3.清空  size=0
void ClearList(SeqList* plist);
//4.扩容操作
Status grow(SeqList* plist);
//5.打印数组元素
void Show(SeqList* plist);
//6.判满操作
Status IsFull(SeqList* plist);
//7.判空操作
Status IsEmpty(SeqList* plist);
//8.头插法  
Status InsertHead(SeqList* plist,ElemType val);
//9.尾插法 
Status InsertTail(SeqList* plist,ElemType val);
//10.指定位置插入 pos---下标  
Status InsertPosVal(SeqList* plist,int posindex, ElemType val);
//11.头删法 
Status DeleteHead(SeqList* plist);
//12.尾删法  
Status DeleteTail(SeqList* plist);
//13.指定位置删除  posindex---下标
Status DeletePos(SeqList* plist, int posindex);
//14.删除指定元素  
Status DeleteVal(SeqList* plist,ElemType val);
//15.查询某个元素返回下标  
int SearchVal(SeqList* plist, ElemType val);
//16.冒泡排序  
void BubbleSort(SeqList* plist);
//17.二分查找(前提数组完全有序)---非递归 
int BinarySearch(SeqList* plist, ElemType val);
//18.二分查找(前提数组完全有序)---递归 
int recursionBinarySearch(SeqList* plist, ElemType val);
//19.将两个有序顺序表合并为一个有序的顺序表   
void MergeList(const SeqList* pla, const SeqList* plb, SeqList* plc);

2-3 头文件设计(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;//数组起始地址
	int length;    //数组总容量
	int size;      //有效数据个数
}SeqList;

//函数实现接口声明
//1.初始化
void initSeqList(SeqList* plist);
//2.销毁   free
void DestoryList(SeqList* plist);
//3. ......
      
#endif // !SEQLIST_H      
防止头文件重复引用
#ifndef SEQLIST_H   //防止seqliat.h被重复引用
#define SEQLIST_H

//......

#endif // !SEQLIST_H 

“被重复引用”是指一个头文件在同一个cpp文件中被include了多次,这种错误常常是由于include嵌套造成的。

#pragma once是编译相关,不一定在每个编译系统上都可以用,移植性差,不过现在基本已经每个编译器都有这个定义了。
#ifndef,#define,#endif 这个是C++语言相关,通过宏定义避免文件多次编译。在所有支持C++语言的编译器上都是有效的,如果程序要跨平台,最好使用这种方式。

2-4 接口实现(seqlist.cpp)

#include<stdio.h>
#include "seqlist.h"
#include <assert.h>
#include <malloc.h>
1.顺序表初始化
void initSeqList(SeqList* plist) {
	assert(plist != NULL);
	plist->data = (ElemType*)malloc(LIST_INIT_CAPACITY * sizeof(ElemType));
	if (plist->data == NULL)return;
	//memset(plist->data, 0, sizeof(ElemType));
	plist->length = LIST_INIT_CAPACITY;//数组初始化长度
	plist->size = 0;
}
2.销毁操作
void DestoryList(SeqList* plist) {
	assert(plist != NULL);
	free(plist->data);//free 释放堆内存
	plist->data = NULL;//防止野指针(悬挂指针)
}
3.清空操作
//删除有效数据
void ClearList(SeqList* plist) {
	assert(plist != NULL);
	plist->size = 0;
}
4.打印数组元素
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");
}
5.扩容操作
Status grow(SeqList* plist) {
	assert(plist != NULL);
	if (plist == NULL)return ERROR;
	int newlength = plist->length * LIST_GROW;

	ElemType* p;
	p = (ElemType*)realloc(plist->data, newlength * sizeof(ElemType));
	if (p == NULL) return OVERFLOW;
	plist->data = p;
	plist->length = newlength;
	return OK;
}
6.判满操作
Status IsFull(SeqList* plist) {
	assert(plist != NULL); 
	return plist->length == plist->size;
}
7.判空操作
Status IsEmpty(SeqList* plist) {
	assert(plist != NULL);
	return plist->size == 0;
}
8.头插法
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;

}
9.尾插法
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;
}
10.指定位置插入 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;
	}
	//从posindex后续数据向后移动
	for (int i = plist->size - 1; i >= posindex; i--) {
		plist->data[i + 1] = plist->data[i];
	}
	plist->data[posindex] = val;
	plist->size++;
	return OK;
}
11.头删法
Status DeleteHead(SeqList* plist) {
	//assert(plist != NULL);
	//if (IsEmpty(plist))return FALSE;
	数据元素向前移动  覆盖前一个
	//for (int i = 1; i < plist->size; i++) {
	//	plist->data[i - 1] = plist->data[i];
	//}
	//plist->size--;
	//return OK;
	 return DeletePos(plist, 0);
}

头删法就是删除下标为0的数据元素。

12.尾删法
Status DeleteTail(SeqList* plist) {
	//assert(plist != NULL);
	//if (IsEmpty(plist))return FALSE;
	//plist->size--;//局限  
	//return OK;
	return DeletePos(plist, plist->size - 1);
}

尾删法就是删除下标为plist->size - 1的数据元素。

13.指定位置删除 posindex—下标
Status DeletePos(SeqList* plist, int posindex) {
	assert(plist != NULL);
	if (IsEmpty(plist)|| posindex > plist->size|| posindex < 0)return FALSE;
	for (int i = posindex; i < plist->size - 1; i++) {
		plist->data[i] = plist->data[i+1];
	}
	plist->size--;
	return OK;
}
14.删除指定元素
Status DeleteVal(SeqList* plist, ElemType val) {
	assert(plist != NULL);
	int index;
	while ((index = SearchVal(plist, val))>=0) {
		DeletePos(plist, index);
	}
	return OK;
}

首先找到元素所在下标,接着按照指定位置删除。

15.查询某个元素返回下标
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;
}
16.冒泡排序
void Swap1(SeqList* plist, int index1, int index2) {
	assert(plist != nullptr);
	if (index1 < 0 || index2 < 0 || index1 >= plist->size || index2 >= plist->size) {
		return ;//exit(EXIT_FALTURE)
	}
	ElemType temp = plist->data[index1];
	plist->data[index1] = plist->data[index2];
	plist->data[index2] = temp;
}
void Swap2(ElemType* p1, ElemType* p2) {
	assert(p1 != nullptr && p2!=nullptr);
	ElemType temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
//冒泡排序
void BubbleSort(SeqList* plist) {
	//assert(plist != NULL);
	assert(plist != nullptr);
	bool flag;
	for (int i = 0; i < plist->size - 1; i++) {//控制趟数
		flag = false;
		for (int j = 0; j < plist->size - 1 - i; j++) {
			if (plist->data[j] > plist->data[j + 1]) {
				//Swap1(plist, j, j + 1); 其他语言
				Swap2(&plist->data[j], &plist->data[j + 1]);//C语言写法
				flag = true;
			}
		}
		if (!flag) {
			break;
		}
	}
}
17.二分查找(前提数组完全有序)—非递归
//非递归二分查找 时间复杂度:O(log2n) 空间复杂度:O(1)
int BinarySearch(SeqList* plist, ElemType val) {
	assert(plist != nullptr);
	int left = 0,right=plist->size-1;
	int index = -1;//返回元素下标
	while (left < right) {
		int middle = (left + right) / 2;
		//int middle = (right - left) / 2 + left;
		//int middle = ((right - left >> 1)) + left;
		if (plist->data[middle] > val) {
			right = middle - 1;
		}
		else if (plist->data[middle] < val) {
			left = middle + 1;
		}
		else {
			index = middle;
		} 
	}
	return index;
}
18.二分查找(前提数组完全有序)—递归
//递归二分查找  (自己调用自己 退出条件 问题规模)空间复杂度:O(log2n)   空间:O(log2n)
int SearchSection(SeqList* plist, int left, int right, ElemType val) {
	if (left > right) return -1;
	int middle = (left + right) / 2;
	if (plist->data[middle] == val)return middle;
	if (plist->data[middle] > val) {
		return SearchSection(plist, left, middle - 1, val);
	}
	else {
		return SearchSection(plist, middle+1, right, val);
	}
}

int recursionBinarySearch(SeqList* plist, ElemType val) {
	assert(plist != nullptr);
	return SearchSection(plist, 0, plist->size-1, val);	
}
19.将两个有序顺序表合并为一个有序的顺序表
void MergeList(const SeqList* pla, const SeqList* plb, SeqList* plc) {
	assert(pla != NULL && plb != NULL && plc != NULL);
	int i = 0, j = 0;

	while (i < pla->size && j < plb->size) {
		if (pla->data[i] > plb->data[j]) {
			//plc->data[x++] = plb->data[j++];
			InsertTail(plc, plb->data[j++]);
		}
		else {
			//plc->data[x++] = pla->data[i++];
			InsertTail(plc, pla->data[i++]);
		}
	}

	if (i >= pla->size) {//pla走完,剩余plb
		while (j < plb->size) {
			//plc->data[x++] = plb->data[j++];
			InsertTail(plc, plb->data[j++]);
		}
	}
	if (j >= plb->size) {//plb走完,剩余pla
		while (i < pla->size) {
			//plc->data[x++] = pla->data[i++];
			InsertTail(plc, pla->data[i++]);
		}
	}
	
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值