评论

收藏

[C++] 【C++线性表总结】期末考试救急!!!

编程语言 编程语言 发布于:2021-12-12 10:32 | 阅读数:480 | 评论:0

线性表(顺序存储结构&链式存储结构)
顺序存储结构,第n个数据元素的存储地址是LOC(an) = LOC(a1)+(n-1)k  其中k表示每个数据元素占用的存储单元的长度)显而易见,这种存储结构,相邻元素在物理位置上也相邻。
通常,我们把采用这种存储结构的线性表称为“顺序表”。
链式存储结构,对于数据元素a1来说,除了存储其自身的信息之外,还需要存储一个指示其直接后继的信息,所以我们引入指针的概念:称存储数据元素信息的域称为数据域,而存储直接后继地址信息的域称为指针域
我们形象地称这种即包含自身数据信息,又包含其直接后继地址信息的数据元素为“结点”。显而易见,这种存储结构,相邻元素在物理位置上不一定相邻,他们之间用指针来表示逻辑关系。
通常,我们把采用这种存储结构的线性表称为“线性链表”。


所有相关函数汇总:

顺序表:
#include<iostream>#include<cstdlib>using namespace std;//传参问题 &/ /* //对引用的所有操作等同于对原对象的所有操作。引用代替指针带来了更干净的代码,可以避免某些bug,比如空指针问题 //直接传参则是传值,当不需要修改原对象时直接传参即可 //顺序表的定义#define MAXSIZE 20#define ADDSIZE 10  //空间不够时每次分配的增量 typedef int ElemType;typedef int Status;#define OK 0#define ERROR -1 typedef struct{  ElemType*data;  int length;  // 顺序表当前长度   int listsize;}SqList;//顺序表的初始化 Status InitList(SqList &L){  L.data=(ElemType*)malloc(MAXSIZE*sizeof(ElemType));  //malloc 分配成功返回指向该内存的地址,失败则返回 NULL  if(!L.data) return ERROR;  L.length=0;  L.listsize=MAXSIZE;  return OK;  } //按值查找元素,找到返回下标,否则返回-1int LocateElem(SqList L,ElemType x){  for(int i=0;i<L.length;i++)  {  if(L.data[i]==x) return i;  }  return -1;} //插入元素,将指定元素插入到指定下标  Status InsertElem(SqList&L,int p,ElemType x) {  //判断插入下标的合法性  if(p<0||p>L.length-1) return ERROR;  //判断存储空间是否够用   //realloc() 修改所指向的内存块的大小,并将新的内存指针返回。  //第一个参数为需要重新分配的内存空间指针,第二个参数为新的内存空间的大小  //realloc 分配成功返回指向该内存的地址,失败则返回 NULL  if(L.length>MAXSIZE)  {  ElemType*newbase=(ElemType*)realloc(L.data,(MAXSIZE+ADDSIZE)*sizeof(ElemType));  if(!newbase) return ERROR;  L.data=newbase; //改为新基址   L.listsize+=ADDSIZE; //增加了存储容量   }  //插入操作  for(int i=L.length-1;i>=p;i--)  {  L.data[i+1]=L.data[i];  }   L.data[p]=x;  L.length++;  return OK; } //删除下标为p的元素,并将该元素的值赋值给变量eStatus DeleteElem(SqList &L,int p,ElemType&e){  //判断下标的合法性  if(p<0||p>L.length-1) return ERROR;  //赋值操作  e=L.data[p];   //删除操作  for(int i=p;i<L.length;i++)  {  L.data[i]=L.data[i+1];  }   L.length--;  return OK;}//显示顺序表void DisplayList(SqList L){  for(int i=0;i<L.length;i++)  {  cout<<L.data[i]<<" ";  }  cout<<endl;} //获得指定位置的元素,并将获得的值赋值给变量eStatus GetElem(SqList L,int p,ElemType&e){  //判断下标的合法性  if(p<0||p>L.length-1) return ERROR;  e=L.data[p];  return OK;} //向顺序表中写入数据int main(){  SqList L;  InitList(L);  int n;  cout<<"请输入顺序表的长度:";  cin>>n;  cout<<"请写入顺序表的数据:";  for(int i=0;i<n;i++)  {  cin>>L.data[i];  L.length++;  }   //测试各函数  DisplayList(L);  int temp1;  GetElem(L,2,temp1);  cout<<"下标为2的值为:"<<temp1<<endl;  int temp2;  DeleteElem(L,4,temp2);  cout<<"删除下标为4的元素: "<<temp2<<endl;  cout<<"现在的顺序表为:";  DisplayList(L);  cout<<endl;  InsertElem(L,5,666);  cout<<"在下标为5的下标处,插入666之后的顺序表为:";   DisplayList(L);  cout<<endl;  }

DSC0000.png


链表:
》》添加结点(头插法/尾插法)
头插法:
DSC0001.png
尾插法:
DSC0002.png
》》链表结点的删除
DSC0003.png
#include<iostream>#include<cstdlib>using namespace std;#define OK 0#define ERROR -1//链表的结点 //一个结点包含数据域和指针域,数据域用来存放数据,指针域负责指向其他结点typedef int ElemType;typedef int Status;typedef struct Node{  ElemType data;  struct Node*next;}*LinkList,LNode;//链表的创建(头插法、尾插法) //创建的所有结点都应该是结构体指针类型,创建时不要忘记分配空间 //头插法创建单链表(逆序建立链表) LinkList HeadInsertCreat(LinkList head){  head=(LinkList)malloc(sizeof(LNode));  head->next=NULL;  cout<<"请输入需要插入的结点个数:";  int n;  cin>>n;  LNode *node=NULL; //定义新结点,指针初始化为空   cout<<"请输入需要插入的数据:";  for(int i=0;i<n;i++)  {  node=(LinkList)malloc(sizeof(LNode));  cin>>node->data;  node->next=head->next;  head->next=node;  }  return head;} //尾插法创建单链表(顺序建立链表)LinkList TailInsertCreat(LinkList head){  head=(LinkList)malloc(sizeof(LNode));  head->next=NULL;  LNode *tail=NULL;  tail=head;  cout<<"请输入需要插入的结点个数:";  int n;  cin>>n;  LNode *node=NULL;  cout<<"请输入需要插入的数据:";  for(int i=0;i<n;i++)  {  node=(LinkList)malloc(sizeof(LNode));  cin>>node->data;  tail->next=node;  tail=node;  }  tail->next=NULL;  return head;} //输出显示链表数据Status DisplayLinkList(LinkList L){  LinkList p;  //判断是否为空  if(L->next==NULL) return ERROR;   else  {  for(p=L->next;p!=NULL;p=p->next) cout<<p->data<<" ";  }  cout<<endl;  return OK;}//删除结点、链表的删除 Status DeleteLinkList(LinkList L,int i,ElemType&e){  LinkList p;  int j;  if(i<0||L->next==NULL) return ERROR; //判断是否为空、指定删除的下标是否合理  //j=i时退出循环 ,此时p在下标i-1的位置,p->next指向要删除的结点   for(p=L,j=0;p->next&&j<i;p=p->next,j++);  if(p->next==NULL) return ERROR;  //删除操作  LinkList q;  q=p->next;  //用 q 临时指向要删除元素   e=q->data;  p->next=q->next; //删除  free(q);  return OK; } //两个链表(都分别为递增序列)合并成一个新链表,要求合并之后的序列递增(可相同的值在一起)Status MergeLinkList(LinkList L1,LinkList L2,LinkList&L){  //创建新链表  L=(LinkList)malloc(sizeof(LNode));  //判断为空链表的情况   LinkList pa,pb;  pa=L1->next;  pb=L2->next;  if(pa==NULL&&pb==NULL) return ERROR;  //合并  LinkList pc=L;   while(pa&&pb)  {  if(pa->data<=pb->data)  {    pc->next=pa;    pc=pa;    pa=pa->next;  }  else  {    pc->next=pb;    pc=pb;    pb=pb->next;  }  }   if(pa) pc->next=pa;  else pc->next=pb;  return OK;} //函数的测试和使用int main(){  LinkList L1,L2;  cout<<"测试头插法逆序建立单链表A:";  L1=HeadInsertCreat(L1);  DisplayLinkList(L1);  cout<<endl;  cout<<"测试尾插法逆序建立单链表B:";  L2=TailInsertCreat(L2);  DisplayLinkList(L2);  cout<<endl;  cout<<"测试删除单链表A中下标为2的结点,并把该结点的数据赋值给变量e:";  ElemType e;   DeleteLinkList(L1,2,e);  cout<<"删除的该结点中的数据为:"<<e<<endl;  cout<<"测试合并两个链表A和B:"<<endl;  cout<<"合并前A:(已保证输入后创建的是增序列) "<<endl;  DisplayLinkList(L1);  cout<<endl;  cout<<"合并前B:(已保证输入后创建的是增序列) "<<endl;  DisplayLinkList(L2);  cout<<endl;  cout<<"合并后: "<<endl;  LinkList L;  MergeLinkList(L1,L2,L);  DisplayLinkList(L);  cout<<endl;  return 0;}

DSC0004.png


关注下面的标签,发现更多相似文章