顺序表的基本操作
//顺序表静态分配内存空间的情况
#include<bits/stdc++.h>
using namespace std;
const int maxsize = 100;
//定义一个顺序表
typedef struct{
int data[maxsize];
int len;//顺序表的长度
}Seqlist;
//初始化一个顺序表
bool InitSeqlist(Seqlist &L){
for(int i = 0;i<maxsize;i++){
L.data[i] = 0;//将申请到的内存空间全部赋值为0
}
L.len = 0;//顺序表的长度最开始为0
return true;//初始化成功
}
//查找一个顺序表中的元素(按位序查找值)
int GetElem(Seqlist L,int i){
if(i<1)return 0;//i值非法,返回0
//因为顺序表随机访问的特点,直接通过下标返回查找的元素
return L.data[i-1];
}
//按值查找位序
int LocateElem(Seqlist L,int e){
//直接遍历顺序表,来与e进行比对
for(int i = 0;i<L.len;i++){
if(L.data[i]==e){
return i+1;//返回下标值
}
}
return -1;//找不到返回0
}
//往顺序表插入一个元素
bool InsertSeqlist(Seqlist &L,int i,int e){
//首先要对i值的非法情况进行判断
if(i<1||i>L.len+1)return false;//直接返回false
if(L.len>=maxsize)return false;//如果顺序表的内存已满,已经不能再添加任何元素了
//注意插入元素,我们要从最后一位把元素向后移动一位
for(int j = L.len;j>=i;j--){
L.data[j] = L.data[j-1];
}
L.data[i-1] = e;//插入元素
L.len++;//表的长度加1
return true;
}
//从顺序表中删除一个元素,对于&符号一定要理解透彻,这里&e指的是我要通过e变量把删除的数据元素带回来
bool DeleteSeqlist(Seqlist &L,int i,int &e){
//对i的非法情况进行判断
if(i<1||i>L.len)return false;
e = L.data[i-1];
//从被删除元素的后一位开始,将数据元素开始向前移动一位
for(int j = i;j<=L.len-1;j++){
L.data[j-1] = L.data[j];
}
L.len--;
return true;//删除成功
}
//创建一个顺序表
void CreateSeqlist(Seqlist &L){
int x;//输入的数据元素
int n;//输入顺序表的元素个数
scanf("%d",&n);
for(int i = 0;i<n;i++){
scanf("%d",&x);
L.data[L.len++] = x;
}
}
//打印一个顺序表
void PrintSeqlist(Seqlist L){
if(L.len==0)printf("list is empty");//顺序表为空
for(int i = 0;i<L.len;i++){
printf("%d ",L.data[i]);
}
printf("\n");
}
int main(){
Seqlist L;//声明一个顺序表
InitSeqlist(L);//初始化一个顺序表
CreateSeqlist(L);//创建一个顺序表
PrintSeqlist(L);//打印一下
printf("请输入插入的位序和值:\n");
int i,e;
scanf("%d%d",&i,&e);//输入插入的位序和值
InsertSeqlist(L,i,e);
PrintSeqlist(L);//打印一下
printf("请输入删除的元素的位序\n");
int j,d;
d = -1;
scanf("%d",&j);
if(DeleteSeqlist(L,j,d)){
printf("删除成功,删除的数是%d\n",d);
}else{
printf("删除失败\n");
}
PrintSeqlist(L);//打印一下
printf("请输入查询元素的值\n");
int sel;//查询的数据元素的值
scanf("%d",&sel);
printf("这个元素位序第%d个",LocateElem(L,sel));
return 0;
}
单链表的基本操作
#include<bits/stdc++.h>
using namespace std;
typedef struct LNode{
int data;//数据域
struct LNode *next;
}LNode,*LinkList;//LNode强调的是一个节点,而LinkList强调的是一个单链表,但在实际意义上二者是等价的,只是为了方便读懂程序
//初始化一个带头结点的单链表
bool InitLinkList(LinkList &L){
L = (LNode*)malloc(sizeof(LNode));//申请一个头结点的内存
if(L==NULL)return false;
L->next = NULL;//单链表初始为空
return true;//初始化成功
}
//创建单链表(头插法),头插法创建的单链表打印出来的数据元素的顺序与输入的顺序是相反的
//LinkList List_HeadInsert(LinkList &L){
// int x;//输入的数据元素
// LNode *s;//插入的节点
// //注意这里L->next一定要指向NULL
// L->next = NULL;//写上是好习惯
// scanf("%d",&x);
// while(x!=9999){
// s = (LNode*)malloc(sizeof(LNode));
// s->data = x;
// s->next = L->next;
// L->next = s;
// scanf("%d",&x);
// }
// return L;
//}
//创建单链表(尾插法)
LinkList List_TailInsert(LinkList &L){
int x;//输入的数据元素
LNode *s,*r = L;//注意r是尾指针,尾指针指的是始终指向最后一个元素的指针,初始时将尾指针指向头结点,设置尾指针的目的是为了方便插入新的元素,但对于删除元素节点没有任何帮助
//L->next == NULL;//初始化一下
printf("开始输入数字,输入9999表示结束:\n");
scanf("%d",&x);
while(x!=9999){
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;//注意要将尾指针指向新的最后一个元素
scanf("%d",&x);
}
r->next = NULL;//最后一个元素的next指针一定指向的是NULL
return L;
}
//获取单链表的长度
int GetLength(LinkList L){
LNode *p = L->next;
int len = 0;
while(p!=NULL){
len++;
p = p->next;
}
return len;
}
//查找第i个节点
LNode * GetNode(LinkList L,int i){
int len = GetLength(L);//获得单链表的表长
if(i<1||i>len)return NULL;
LNode *p = L->next;
int j = 1;//注意这里j要等于1
while(p!=NULL&&j<i){
p = p->next;
j++;
}
return p;//返回节点
}
//单链表的插入,插入又分为前插和后插
//后插,在p节点后插入一个新的节点q
bool InsertNextNode(LNode *p,int e){
//先判断p和q节点是否非法,两个节点都为空
if(p==NULL)return false;
//为新节点q分配内存空间
LNode * q = (LNode*)malloc(sizeof(LNode));
if(q==NULL)return false;//内存分配失败
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
//前插
bool InsertFrontNode(LNode *p,int e){
//先判断p和q节点是否非法,两个节点都为空
if(p==NULL)return false;
//为新节点q分配内存空间
LNode * q = (LNode*)malloc(sizeof(LNode));
if(q==NULL)return false;
//注意,前插运用到了一个技巧,通过交换两个节点的数据域的值,来完成前插,实际上我们完成的是后插操作
q->data = p->data;
q->next = p->next;
p->next = q;
p->data = e;
return true;
}
//删除(删除的一般方法就是要找到被删除元素节点的前驱节点,在单链表中删除操作的时间复杂度(除了删除第一个元素)一定与表长有关)
//删除单链表中的第i个节点
bool DeleteNode(LinkList &L,int i,int &e){
int len = GetLength(L);//获得单链表的表长
if(i<1||i>len)return false;
//找到第i-1个节点p,也就是被删除节点的前驱节点
LNode * p = GetNode(L,i-1);
//被删除节点q
LNode * q = GetNode(L,i);
//修改指针
p->next = q->next;
e = q->data;
free(q);//释放被删除节点
return true;//删除成功
}
//向指定位序插入一个节点
bool InsertNode(LinkList &L,int i, int e){
int len = GetLength(L);//获得单链表的表长
if(i<1||i>len+1)return false;
//找到插入位置的前驱节点
LNode *p = GetNode(L,i-1);
InsertNextNode(p,e);//后插
return true;
}
//打印单链表
void PrintLinkList(LinkList L){
if(L->next==NULL)printf("单链表是空的\n");
LNode *p = L->next;
while(p!=NULL){
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
int main(){
LinkList L;//声明一个单链表
InitLinkList(L);//初始化一个单链表
List_TailInsert(L);//头插创建单链表
PrintLinkList(L);//打印
printf("输入删除节点的位序i:\n");
int del,ele;//删除节点的位序i和返回节点的数值
ele = -1;
scanf("%d",&del);
if(DeleteNode(L,del,ele)){
printf("删除成功! 删除的数是 %d\n",ele);
}else{
printf("失败\n");
}
PrintLinkList(L);//打印
printf("输入插入节点的位序i和插入的数值\n");
int ins,vau;//插入节点的位序i和插入的数值
scanf("%d%d",&ins,&vau);
if(InsertNode(L,ins,vau)){
printf("插入成功!\n");
PrintLinkList(L);
}else{
printf("失败\n");
}
return 0;
}
前插法创建的单链表和尾插法创建的单链表(也就是数据的输入顺序)是相反的,可以通过前插法实现将单链表的元素逆序排列。
#include<bits/stdc++.h>
using namespace std;
typedef struct LNode{
int data;//数据域
struct LNode *next;//指针
}LNode,*LinkList;
//初始化单链表
bool InitList(LinkList &L){
L = (LNode*)malloc(sizeof(LNode));
if(L==NULL)return false;//内存分配不成功
L->next = NULL;
return true;//初始化成功
}
//尾插法
LinkList List_TailInsert(LinkList &L){
int x;
L = (LNode*)malloc(sizeof(LNode));
L->next = NULL;//初始化单链表,这是一个好习惯
LNode *s,*r = L;
scanf("%d",&x);
while(x!=9999){
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s;
r = s;
scanf("%d",&x);
}
r->next = NULL;
return L;
}
//头插法
LinkList List_TailHeadInsert(LinkList &L){
LNode *s;
int x;//输入的数
L = (LNode*)malloc(sizeof(LNode));
//注意这里的头结点一定要初始化执行NULL
L->next = NULL;
printf("请输入数据,输入9999,代表结束\n");
scanf("%d",&x);
while(x!=9999){
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d",&x);
}
return L;
}
//L1代表倒序的单链表,L代表原单链表
LinkList List_Reverse(LinkList &L1,LinkList &L){
L1 = (LNode*)malloc(sizeof(LNode));
L1->next = NULL;//头结点初始化
LNode *p = L->next;
while(p!=NULL){
LNode *s = (LNode*)malloc(sizeof(LNode));
s->data = p->data;
s->next = L1->next;
L1->next = s;
p = p->next;
}
return L1;
}
//打印单链表
void PrintList(LinkList L){
LNode *p = L->next;
while(p!=NULL){
printf("%d ",p->data);
p = p->next;
}
}
int main(){
LinkList L;
LinkList L1;
InitList(L);//初始化单链表
InitList(L1);//初始化单链表
//List_TailInsert(L);
List_TailHeadInsert(L);//头插法建立的单链表,与输入成逆序
printf("打印头插法建立的单链表为:\n");
PrintList(L);
printf("\n");
printf("通过头插法将单链表逆置\n");
List_Reverse(L1,L);//又通过头插法将顺序逆置过来
PrintList(L1);
return 0;
}
List_Reverse函数实际上是利用已经建立好的单链表L中的数据元素,使用头插法再建立一个单链表L1,顺序自然能够得到逆置。