十月份就要考数据结构了,为了这次考试能顺利通过。同时数据结构在开发过程中也是相当重要的,但是以前从来就没有系统地学习过。所以正好借此机会好好地学习下数据结构,一方面是为了通过考试,另一方面也把数据结构和算法这一块的基础打牢一点,真是一举两得啊。
我打算把这一部分写成一个系列,分为C#和C语言两个版本,每周发布两篇。从线性表开始,这一篇主要总结线性表之顺序表的相关操作,主要分以下几个部分来总结。
1,什么是线性表?
2,线性表的两种存储结构?
3,顺序表的存储结构表示?
4,顺序表的常见操作和代码实现?
1,什么是线性表
线性表就是关系中的一对一的关系,如果是一对多就用树来表示,如果多对多就用网状来表示。
线性表具有以下四个特征:
1> 有且只有一个“首”元素
2> 有且只有一个“尾”元素
3> 除“首”元素外,其余元素都有唯一的后继元素。
4> 除“尾”元素外,其余元素都有唯一的前驱元素。
2,线性表的两种存储结构
1> 顺序表,即线性表用顺序存储结构保存数据,数据是连续的。这一篇文章总结的就是顺序表
2> 链表,即线性表用链式存储结构保存数据,数据不连续。
3,顺序表的存储结构表示
注:C#和C语言中的数组下标都是从0开始的。
4,顺序表的常见操作和代码实现
顺序表主要有以下常见操作,我们一般用数组来保存数据
1,初始化
思路:将数组的长度length设为0,时间复杂度为O(1)。
2,求顺序表的长度
思路:获取数组的length值,时间复杂度为O(1)。
3,插入元素
思路:分两种情况,一种是插入位置在数组的末尾,这种情况与添加元素相同。另一种情况是插入位置在数组的开始,这时候被插入元素的后续元素都要依次向后移动一位,也就是说整个数组都会移动,所以时间复杂度为O(n)。
4,删除元素
思路:同样分两种情况,一种是删除位置在数组的末尾,不用移动任何元素,因此时间复杂度为O(1);另一种情况是删除位置在数组的开始,这时被删除元素的后续元素都要依次向前移动一位,因此时间复杂度为O(n)。
5,按序号查找元素
思路:因为顺序表的存储地址是连续的,所以第n个元素的地址公式为:(n-1)*单元存储长度,不用移动任何元素,因此时间复杂度为O(1)。
6,按关键字查找元素
思路:一般用for循环,调用IComparable接口的CompareTo()方法去比较,因此时间复杂度为O(n)。
项目结构:
实现代码:
C#版
namespace DS.Model { /// <summary> /// 学生实体 /// </summary> public class Student { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } } } namespace DS.BLL { /// <summary> /// 顺序表操作业务逻辑类 /// </summary> public class SeqListBLL { /// <summary> /// 初始化 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqListType"></param> public static void InitSeqList<T>(SeqListType<T> seqList) { seqList.ListLen = 0; } /// <summary> /// 获取顺序表的长度 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqList"></param> /// <returns></returns> public static int GetSeqListLen<T>(SeqListType<T> seqList) { return seqList.ListLen; } /// <summary> /// 插入元素(在第n个元素之前的位置插入新元素) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqList"></param> /// <param name="n"></param> /// <param name="data"></param> /// <returns></returns> public static bool Insert<T>(SeqListType<T> seqList, int n, T data) { //检查数组是否已满 if (seqList.ListLen >= seqList.MaxSize) return false; //检查n的位置是否超出范围 if (n < 1 || n > seqList.ListLen + 1) return false; //若插入数据位置不在表尾 if (n <= seqList.ListLen) { //将要插入位置之后元素依次向后移动一位 for (int i = seqList.ListLen - 1; i >= n-1; i--) { seqList.ListData[i + 1] = seqList.ListData[i]; } } //将数据插入到位置为n的位置并将数组的长度加1 seqList.ListData[n-1] = data; seqList.ListLen++; return true; } /// <summary> /// 删除元素(删除第n个元素) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqList"></param> /// <param name="n"></param> /// <returns></returns> public static bool Delete<T>(SeqListType<T> seqList, int n) { //判断数组是否为空 if (seqList.ListLen == 0) return false; //判断n的位置是否合法 if (n < 1 || n > seqList.ListLen) return false; //如果删除不是最后位置 if (n < seqList.ListLen) { //将删除位置后继元素依次前移 for (int i = n; i < seqList.ListLen; i++) { seqList.ListData[i-1] = seqList.ListData[i]; } } //表长减1 seqList.ListLen--; return true; } /// <summary> /// 查找第n个元素 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqList"></param> /// <param name="n"></param> /// <returns></returns> public static T GetDataByIndex<T>(SeqListType<T> seqList, int n) { //检查位置是否超出范围 if(n<1||n>seqList.ListLen) return default(T); return seqList.ListData[n-1]; } /// <summary> /// 按关键字查找元素 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="W"></typeparam> /// <param name="seqList"></param> /// <param name="key"></param> /// <param name="where"></param> /// <returns></returns> public static T GetDataByKey<T, W>(SeqListType<T> seqList,string key,Func<T,W> where) where W : IComparable { for (int i = 0; i < seqList.ListLen; i++) { if (where(seqList.ListData[i]).CompareTo(key) == 0) { return seqList.ListData[i]; } } return default(T); //值类型返回0,引用类型返回null } } /// <summary> /// 封装顺序表 /// </summary> /// <typeparam name="T"></typeparam> public class SeqListType<T> { private const int maxSize = 100; public int MaxSize { get { return maxSize; } }//表的最大长度 //初始化长度为100的数组保存数据 public T[] ListData = new T[maxSize]; //顺序表的长度 public int ListLen { get; set; } } } namespace SeqList.CSharp { class Program { static void Main(string[] args) { //定义一个顺序表实例 SeqListType<Student> seqList = new SeqListType<Student>(); //初始化 Console.WriteLine("****************初始化**********************\n"); SeqListBLL.InitSeqList<Student>(seqList); Console.WriteLine("初始化后表的长度为:{0}",SeqListBLL.GetSeqListLen<Student>(seqList)); //插入数据 Console.WriteLine("\n****************插入三条数据**********************\n"); if (!SeqListBLL.Insert<Student>(seqList, 1, new Student { ID = 1, Name = "james", Age = 28 })) Console.WriteLine("插入失败"); else Console.WriteLine("插入成功"); if (!SeqListBLL.Insert<Student>(seqList, 1, new Student { ID = 2, Name = "kobe", Age = 33 })) Console.WriteLine("插入失败"); else Console.WriteLine("插入成功"); if (!SeqListBLL.Insert<Student>(seqList, 1, new Student { ID = 3, Name = "wade", Age = 31 })) Console.WriteLine("插入失败"); else Console.WriteLine("插入成功"); Display(seqList); //删除数据 Console.WriteLine("\n****************删除一条数据**********************\n"); SeqListBLL.Delete<Student>(seqList,1); Console.WriteLine("删除成功"); Display(seqList); //查找元素 Console.WriteLine("****************查找元素by位置**********************\n"); Console.WriteLine("查找第{0}个元素",2); Student student= SeqListBLL.GetDataByIndex<Student>(seqList,2); if (student != null) Console.WriteLine("ID:" + student.ID + ",Name:" + student.Name + ",Age:" + student.Age); else Console.WriteLine("没有找到数据"); //查找元素by关键字 Console.WriteLine("****************查找元素by关键字**********************\n"); Console.WriteLine("查找关键字为{0}的元素", "kobe"); Student student1 = SeqListBLL.GetDataByKey<Student, string>(seqList,"kobe",p=>p.Name); if (student1 != null) Console.WriteLine("ID:" + student1.ID + ",Name:" + student1.Name + ",Age:" + student1.Age); else Console.WriteLine("没有找到数据"); //获取表的长度 Console.WriteLine("****************获取表的当前长度**********************\n"); int currentLen= SeqListBLL.GetSeqListLen<Student>(seqList); Console.WriteLine("当前表中有{0}个元素", currentLen); Display(seqList); Console.ReadKey(); } /// <summary> /// 显示数据 /// </summary> /// <param name="seqList">顺序表对象</param> private static void Display(SeqListType<Student> seqList) { Console.WriteLine("****************展示数据**********************"); if (seqList == null || seqList.ListLen == 0) { Console.WriteLine("没有数据"); return; } for (int i = 0; i < seqList.ListLen; i++) { Console.WriteLine("ID:" + seqList.ListData[i].ID + ",Name:" + seqList.ListData[i].Name + ",Age:" + seqList.ListData[i].Age); } } } }
运行结果:
C语言版
/*包含头文件*/ #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h" /*定义常量,类似于C#中的const*/ #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 20 /*定义类型的同义字*/ typedef int Status; typedef int ElemType; typedef struct //定义顺序表 { ElemType data[MAXSIZE]; int length; }SeqList; /*初始化*/ Status InitSeqList(SeqList *seqList) //*L表示指向顺序表SeqList的指针 { seqList->length=0; return OK; } /*求顺序表的长度*/ int GetSeqListLen(SeqList *seqList) { return seqList->length; } /*插入元素(在第n个元素之前的位置插入新元素)*/ Status Insert(SeqList *seqList,int n,ElemType e) { int k; //检查数组是否已满 if (seqList->length>=MAXSIZE) return ERROR; //检查n的位置是否超出范围 if (n<1||n>seqList->length+1) return ERROR; //若插入数据位置不在表尾 if (n<=seqList->length) { //将要插入位置之后元素依次向后移动一位 for (k=seqList->length-1;k>=n-1;k--) { seqList->data[k+1]=seqList->data[k]; } } //将新元素插入到腾出的位置,并将表长加1 seqList->data[n-1]=e; seqList->length++; return OK; } /*删除元素(删除第n个元素)*/ Status Delete(SeqList *seqList,int n,ElemType *e) { int k; //判断数组是否为空 if (seqList->length==0) return ERROR; //判断n的位置是否合法 if (n<1||n>seqList->length) return ERROR; *e=seqList->data[n-1]; //如果删除不是最后位置 if (n<seqList->length) { //将删除位置后继元素依次前移 for (k=n;k<seqList->length;k++) { seqList->data[k-1]=seqList->data[k]; } } //表长减1 seqList->length--; return OK; } /*查找第n个元素*/ int GetDataByIndex(SeqList *seqList,int n) { //检查位置是否超出范围 if (n<1||n>seqList->length) return ERROR; return seqList->data[n-1]; } /*打印结果*/ void Display(SeqList *seqList) { int i; printf("\n********展示数据********\n"); for (i=0;i<seqList->length;i++) { Visit(seqList->data[i]); } printf("\n"); } Status Visit(ElemType c) { printf("%d\n",c); return OK; } void main() { //声明变量 SeqList seqList; //创建顺序表 int j,k; Status i; ElemType elem; printf("\n*****************初始化************************\n"); i=InitSeqList(&seqList);//&表示地址 printf("初始化后表的长度为:%d\n",seqList.length); printf("\n*****************插入五条数据************************\n"); for (j=1;j<=5;j++) { i=Insert(&seqList,1,j);//在表头依次插入1~5 } Display(&seqList); printf("\n*****************删除一条数据************************\n"); i=Delete(&seqList,1,&elem); if (i==OK) printf("删除成功\n"); Display(&seqList); printf("\n*****************查找元素by位置************************\n"); k=GetDataByIndex(&seqList,2); printf("第2个元素为%d\n",k); printf("\n*****************获取表的当前长度************************\n"); k=GetSeqListLen(&seqList); printf("当前表中有%d个元素\n",k); getchar(); }
运行结果: