文字模块
代码模块
一.顺序表
1.定义
typedef int Datatype: //Datatype可为任何类型,在此为int
#define MAXSIZE 1024 //线性表可能的最大长度,假设为1024
typedef struct{
Datatype data[MAXSIZE];
int last;
}SequenList;
2.基本运算
1.建立顺序表L
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define MAXSIZE 1024
typedef char Datatype;
typedef struct{
Datatype data[MAXSIZE];
int last; //指示线性表终端节点的位置
}SequenLIst;
//建立顺序表L;
SequenList *L;
SequenList *Create(){
int i=0; char ch;
L=(SequenList*)malloc(sizeof(SequenList)); //分配顺序表空间
L->last=-1;
printf("请输入顺序表L中的元素,以字符'#'结束.\n");
while((ch=getche())!='#'){
L->data[i++]=ch;
L->last++;
}
return L;
}
2.插入数据
将新节点x插入顺序表L的第i个位置上
int Insert(SequenList *l,char x,int i){
//考虑到表空间溢出,非法位置两问题
int j;
if(L->last>=MAXSIZE-1) {
printf("overflow\n");
return 0;
}
else if((i<1)||(i>(L->last+2))){
printf("errror\n");
retrurn 0;
}
else{
for(j=L->last;j>=i-1;j--){
L->data[j+1]=L->data[j]; //结点后移
}
L->data[i-1]=x;
L->last+=1;
}
return 1;
}
3. 输出顺序表
void Output(SequenList *L){
printf("\n 顺序表L中的元素为:");
for(int i=0;i<=L->last;i++){
printf("%c",L->data[i]);
}
}
4.主程序
int main(){
char ch;
int i,ret;
L=Create();
scanf("%c",&ch);
scanf("%d",&i);
ret=Insert(L,ch,i);
if(ret){
Output(L);
}
return 0;
}
二、链表
链表的每个节点采用结构体的形式组织:
typedef struct student{
int num;
char name[20];
struct student *next;
}STU;
链表节点分为两个域
数据域:存放各种实际的数据,如:num、score等
指针域:存放下一节点的首地址,如:next等. 因此链表的存储密度小于顺序表
链表的操作:
链表最大的作用是通过节点把离散的数据链接在一起,组成一个表,这大概就是链表 的字面解释了吧。 链表常规的操作就是节点的插入和删除,为了顺利的插入,通常一条链 表我们会人为地规定一个根节点,这个根节点称为生产者。通常根节点还会有一个节点计 数器,用于统计整条链表的节点个数,具体见图3中的 root_node。
双向链表
双向链表与单向链表的区别就是节点中有两个节点指针,分别指向前后两个节点,其 它完全一样。有关双向链表的文字描述参考单向链表小节即可,有关双向链表的示意图具体见图4
以双向链表为例, 链表是通过节点把离散的数据链接成一个表,通过对节点的插入和删除操作从而实现 对数据的存取。而数组是通过开辟一段连续的内存来存储数据,这是数组和链表最大的区 别。数组的每个成员对应链表的节点,成员和节点的数据类型可以是标准的 C 类型或者是 用户自定义的结构体。数组有起始地址和结束地址,而链表是一个圈,没有头和尾之分, 但是为了方便节点的插入和删除操作会人为的规定一个根节点。
双向链表结构:
typedef char Datatype;
typedef struct node{
Datatype data;
struct dnode *prior,*next;
}Dlinklist;
Dlinklist *head;
删除节点:
void DeleteNode(DlinkLIst *p){
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
}
插入节点:
// 在节点p前插入新节点
void InsertBefore(DlinkList *p,datatype x){
DlinkList *s;
s=(DlinkList *)malloc(sizeof(DlinkList));
s->data=x;
s->prior=p->prior;
s->next=p;
p->prior->next=s;
p->prior=s;
}
操作
① 创建链表
#include<stdio.h>
#include<stdlib.h>
//定义结点结构体
typedef struct student{
// 数据域
int num; //学号
int score; //分数
char name[20]; //姓名
// 指针域
struct student *next;
}STU;
// 创建头节点
void link_creat_head(STU **p_head,STU *p_new)
{
STU *p_mov=*p_head; //*p_head是头节点
if(*p_head==NULL){
//对头结点进行初始化
*p_head=p_new;
p_new->next=NULL;
}
else{
while(p_mov->next!=NULL){
p_mov=p_mov->next; //找到原有链表最后一个节点
}
p_mov->next=p_new;
p_new->next=NULL;
}
}
主程序
int main(){
STU *head=NULL,*p_new=NULL;
int num;
printf("请输入链表初始个数\n");
scanf("%d",&num);
for(int i=0;i<num;i++){
p_new=(STU*)malloc(sizeof(STU)); 申请一个新节点
printf("请输入学号,分数,名字: \n"); 给新结点赋值
scanf("%d %d %s",&p_new->num,&p_new->score,p_new->name);
link_creat_head(&head,p_new); //将新节点加入链表
}
return 0;
}
②链表的遍历
第一步:输出第一个节点的数据域,输出完毕后,让指针保存后一个节点的地址
第二步:输出移动地址对应的节点的数据域,输出完毕后,指针继续后移 ,直到节点指针域为NULL
void link_print(STU *head){
STU *p_mov;
p_mov=head;
while(p_mov->next!=NULL){
printf("num=%d score=%d name:%s\n",p_mov->num,p_mov->score,p_mov->name);
p_mov=p_mov->next;
}
}
③链表的释放
重新定义一个指针q,保存p指向节点的地址,然后p后移保存下一个节点的地址,然后释放q对应的节点,以此类推,直到p为NULL为止
void link_free(STU **p_head){
STU *pb=*p_head;
while(p_head!=NULL){
pb=*p_head;
free(pb);
pb=NULL;
}
}
④链表节点的查找
先对比第一个结点的数据域是否是想要的数据,如果是就直接返回,如果不是则继续查找下 一个结点,如果到达最后一个结点的时候都没有匹配的数据,说明要查找数据不存在
//按照学号查找
STU * link_search_num(STU *head,int num){
STU *p_mov;
p_mov=head;
while(p_mov!=NULL){
if(p_mov==num){
return p_mov;
}
p_mov=p_mov->next;
}
return NULL;
}
//按照姓名查找
STU * link_search_name(STU *head,char *name){
STU *p_mov;
p_mov=head;
while(p_mov!=NULL){
if(strcmp(p_mov->name,name)==0){
return p_mov;
}
p_mov=p_mov->next;
}
return NULL;
}
⑤链表节点的删除
如果链表为空,不需要删除 如果删除的是第一个结点,则需要将保存链表首地址的指针保存第一个结点的下一个结点的 地址 如果删除的是中间结点,则找到中间结点的前一个结点,让前一个结点的指针域保存这个结 点的后一个结点的地址即可
void link_delete_num(STU **p_head,int num){
STU *pb,*pf;
pb=pf-*p_head;
if(*p_head==NULL){
return;
}
while(pb->num!=num && pb->next!=NULL){
pf=pb;
pb=pb->next;
}
if(pb->num==num){
if(pb==*p_head){
*p_head=pb->next;
}
else{
pf->next=pb->next;
}
free(pb);
pb=NULL;
}
else{
printf("没有您要删除的节点\n");
}
}
⑥链表中插入一个节点
情况(按照从小到大):
如果链表没有结点,则新插入的就是第一个结点。
如果新插入的结点的数值最小,则作为头结点。
如果新插入的结点的数值在中间位置,则找到前一个,然后插入到他们中间。
如果新插入的结点的数值最大,则插入到最后。