数据结构之线性表(史上最全!---纯C语言!---涉及到二级指针!)

个人blog

线性表

对于非空的线性表或线性结构,其特点是:
(1)存在唯一的一个被称作“第一个”的数据元素:
(2)存在唯一的一个被称作“最后-一个"的数据元素;
(3)除第一个之外,结构中的每个数据元素均只有一个前驱;
(4)除最后一个之外,结构中的每个数据元素均只有一个后继。

1.顺序存储

线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素,这种表示也称做线性表的顺序存储结构或顺序映像。通常,称这种存储结构的线性表为顺序表。特点:逻辑上相邻的数据元素,物理空间上也相邻。

基本操作:查找 插入 删除

完成了基本操作实现 并给出验证 可直接运行 纯C语言环境

#include<stdio.h>
#include<windows.h>
#define maxsize 100
typedef int Datatype;
typedef struct Sequential_list{
    Datatype *data; // 存储空间的基地址
    int length; // 保存于线性表当前长度
}Sqlist; 

void InitList(Sqlist *p); //构造一个空线性表
bool ListInsert(Sqlist *p,int i,Datatype t);//插入操作
bool ListDelete(Sqlist *p,int i,Datatype *t);//删除操作
void DestroyList();//销毁整个线性表
void ClearList();//清空整个线性表
void ListEmpty();//判断是否为空表
void ListLength();//返回线性表元素个数
void GetElem();//返回L中第i个数据元素的值
int LocateElem(Sqlist L,Datatype t);//返回与e相等的元素的位置序号
void PriorElem();//返回元素前驱
void NextElem();//返回元素后驱
void PrintElem(Sqlist *p);//打印所有元素

void InitList(Sqlist *p){

        p -> length  = 0 ;
        p -> data = (Datatype*)malloc((sizeof(Datatype))*maxsize); // == new Datatype[maxsize];
        if(!p->data) exit(-1);

}

int LocateElem(Sqlist L,Datatype t){
        int i;
        for(i=0 ; i<=L.length ; i++){
            if(L.data[i]==t)
                return i+1;
        }
        return -1;

}

bool ListInsert(Sqlist *p,int i,Datatype t){

        int j;

        if((i<1)||(i>p->length+1)) return false;
        
        if(p->length == maxsize) return false;
        
        for(j=p->length-1;j>=i-1;j--){
            p->data[j+1] = p->data[j];
        }
        
        p->data[i-1] = t;
        p->length++;
        return true;

}

bool ListDelete(Sqlist *p,int i,Datatype *t){

        int j;
        int temp; // 暂存将要删除的元素
        
        if((i<1)||(i>p->length)) return false;

        *t = p->data[i-1]; // 返回删除元素值

        for(j=i;j<=p->length-1;j++){
            p->data[j-1] = p->data[j];
        }

        p->length--;
        return true;

        
}

void PrintElem(Sqlist *p){

    int i;
    printf("Elements:\n");
    for(i = 0; i <= p->length-1; i++){
        printf("%d  ",p->data[i]);
        if(i==5)
            printf("\n");
    }
    printf("\n");
}

int main(){

    Sqlist myslist;
    Datatype k;

    InitList(&myslist);
    ListInsert(&myslist,1,3);
    ListInsert(&myslist,1,4);
    ListInsert(&myslist,1,6);

    PrintElem(&myslist);

    ListDelete(&myslist,2,&k);

    PrintElem(&myslist);

    printf("DeleteElem: %d\n",k);

    system("pause");
    return 0;
}

完整代码:(在我的机器上运行无误,请自行测试)

#include<stdio.h>
#include<windows.h>
#define maxsize 100
typedef int Datatype;
typedef struct Sequential_list{
    Datatype *data; // 存储空间的基地址
    int length; // 保存于线性表当前长度
}Sqlist; 

void InitList(Sqlist *p); //构造一个空线性表
bool ListInsert(Sqlist *p,int i,Datatype t);//插入操作
bool ListDelete(Sqlist *p,int i,Datatype *t);//删除操作
void DestroyList(Sqlist *p);//销毁整个线性表
void ClearList(Sqlist *p);//清空整个线性表
bool ListEmpty(Sqlist *p);//判断是否为空表
int ListLength(Sqlist *p);//返回线性表元素个数
Datatype GetElem(Sqlist *p,int i);//返回L中第i个数据元素的值
int LocateElem(Sqlist L,Datatype t);//返回与e相等的元素的位置序号
Datatype PriorElem(Sqlist *p,Datatype e);//返回元素前驱
Datatype NextElem(Sqlist *p,Datatype e);//返回元素后驱
void PrintElem(Sqlist *p);//打印所有元素

void DestroyList(Sqlist *p){
    free(p->data);
    p->length = 0;
}

void ClearList(Sqlist *p){

    int i;
    for(i=0;i<p->length;i++)
        p->data[i] = 0;
    p->length = 0;

}

bool ListEmpty(Sqlist *p){

    if(p->length == 0)
        return true;
    return false;

}

int ListLength(Sqlist *p){
    
    return p->length;

}

Datatype GetElem(Sqlist *p,int i){

    if((i<1)||(i>p->length)) return 0xffffffff;
    return p->data[i-1];

}

Datatype PriorElem(Sqlist *p,Datatype e){

    int i;
    for(i=0;i<p->length;i++){
		if(p->data[i]==e){
			if(i==0)	return 0xffffffff;
			return p->data[i-1];
		}
	}
	return 0xffffffff;

}

Datatype NextElem(Sqlist *p,Datatype e){

    int i;
    for(i=0;i<p->length;i++){
        if(p->data[i]==e){
			if(i==p->length-1)
				return 0xffffffff;
			return p->data[i+1]
		};
	}
	return 0xffffffff;

}


void InitList(Sqlist *p){

        p -> length  = 0 ;
        p -> data = (Datatype*)malloc((sizeof(Datatype))*maxsize); // == new Datatype[maxsize];
        if(!p->data) exit(-1);

}

int LocateElem(Sqlist L,Datatype t){
        int i;
        for(i=0 ; i<=L.length ; i++){
            if(L.data[i]==t)
                return i+1;
        }
        return -1;

}

bool ListInsert(Sqlist *p,int i,Datatype t){

        int j;

        if((i<1)||(i>p->length+1)) return false;
        
        if(p->length == maxsize) return false;
        
        for(j=p->length-1;j>=i-1;j--){
            p->data[j+1] = p->data[j];
        }
        
        p->data[i-1] = t;
        p->length++;
        return true;

}

bool ListDelete(Sqlist *p,int i,Datatype *t){

        int j;
        int temp; // 暂存将要删除的元素
        
        if((i<1)||(i>p->length)) return false;

        *t = p->data[i-1]; // 返回删除元素值

        for(j=i;j<=p->length-1;j++){
            p->data[j-1] = p->data[j];
        }

        p->length--;
        return true;

        
}

void PrintElem(Sqlist *p){

    int i;
    printf("Elements:\n");
    for(i = 0; i <= p->length-1; i++){
        printf("%d  ",p->data[i]);
        if(i==5)
            printf("\n");
    }
    printf("\n");
}

int main(){

    Sqlist myslist;
    Datatype k;

    InitList(&myslist);
    ListInsert(&myslist,1,3);
    ListInsert(&myslist,1,4);
    ListInsert(&myslist,1,6);

 /*   PrintElem(&myslist);

    ListDelete(&myslist,2,&k);

    PrintElem(&myslist);

    printf("DeleteElem: %d\n",k);

    ClearList(&myslist);

    PrintElem(&myslist); */

    if(ListEmpty(&myslist)) printf("Empty \n");
    else printf("Not Empty \n");

    printf("%d ",GetElem(&myslist,2));
    printf("%d ",PriorElem(&myslist,4));
    printf("%d ",NextElem(&myslist,4)); 

    DestroyList(&myslist);

    PrintElem(&myslist);

    system("pause");
    return 0;
}

2. 链式存储

线性表链式存储结构的特点是:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素a与其直接后继数据元素a1+之间的逻辑关系,对数据元素a来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。
  • 备注:根据链表结点所含指针个数、指针指向和指针连接方式,可将链表分为单链表、循环链表、双向链表、二叉链表、十字链表、邻接表、邻接多重表等。其中单链表、循环链表和双向链表用于实现线性表的链式存储结构,其他形式多用于实现树和图等非线性结构。
  • 以下实现为单链表

基本操作:查找 插入 删除

完成了基本操作实现 并给出验证 可直接运行 纯C语言环境

#include<stdio.h>
#include<windows.h>
#define maxsize 100
typedef int Datatype;
typedef struct Lnode{
    Datatype data; //数据域
    struct Lnode* next; //指针域
    int length; //当前链表长度
}LNode,*LinkList;

void InitList(LinkList *p); //构造一个空线性表
bool ListInsert(LinkList *p,int x,Datatype e);//插入操作(插入到第几个位置--类似于头插法)
bool ListDeleteOfIndex(LinkList *p,int x);//删除操作(根据位置)
bool ListDeleteOfEle(LinkList *p,Datatype e);//删除操作(根据值)
Datatype GetElem(LinkList *p,int i);//返回L中第i个数据元素的值

void DestroyList(LinkList *p);//销毁整个线性表
void ClearList(LinkList *p);//清空整个线性表
void ListEmpty(LinkList *p);//判断是否为空表
void ListLength(LinkList *p);//返回线性表元素个数
int LocateElem(LinkList *p,Datatype d);//返回与e相等的元素的位置序号
Datatype PriorElem(LinkList *p,int i);//返回元素前驱
Datatype NextElem(LinkList *p,int i);//返回元素后驱
void PrintElem(LinkList *p);//打印所有元素


void InitList(LinkList *p){ //二级指针: P指向MLlist指针的地址

    *p = (LNode*)malloc(sizeof(LNode)); 
    //给MLlist所在分配内存空间  *p = MLlist 
    // 可用printf("%d\n",&(*p));检验

    if(!(*p)) exit(-1);         //分配失败退出
    
    (*p) -> next = NULL; 
    (*p) -> length = 0 ;
    //(*p)->data = 3; 
    //令此结点为空作为head结点           
    //给所在内存空间赋值
    //printf("%d\n", (*p)->data); 
    //free(*p);
}

bool ListInsert(LinkList *p,int i,Datatype e){

    int x;   
    int len = (*p)->length;
    LinkList t = (*p); // 标号:标记头节点为0
    
    if((i<1)||(i>len+1)) return false;

    for(x = 1 ; x < i ; x++)
        t = t->next;
    
    LNode* L = (LNode*)malloc(sizeof(LNode));

    L->next = t->next;
    L->data = e;
    t->next = L;
    (*p)->length++;

    return true;

}

bool ListDeleteOfIndex(LinkList *p,int x){

    LinkList t1 = (*p);
    LinkList t2 = (*p)->next; //寻找所在结点
    int len = (*p)->length;
    int i;
    
    if((x<1)||(x>len)) return false;

    for(i = 1 ; i < x ; i++){  
        t1 = t1->next;
        t2 = t2->next;
    }

    t1->next = t2->next;
    (*p)->length--;
    free(t2);
    return true;

}

bool ListDeleteOfEle(LinkList *p,Datatype e){

    LinkList t1 = (*p);
    LinkList t2 = (*p)->next; //寻找所在结点
    
    while(true){
        if(t2==NULL)
            return false;    
        if(t2->data==e){
            break;
        }
        t1 = t1 -> next;
        t2 = t2 -> next;  
    }

    t1->next = t2->next;
    (*p)->length--;    
    free(t2);
    return true;

}

Datatype GetElem(LinkList *p,int i){

    LinkList t = (*p)->next;
    int len = (*p)->length;
    int k;
    if((i<1)||(i>len)) return 0xffffffff;
    for(k = 1; k < i; k++){
        t = t->next;
    }
    return t->data;

}

Datatype PriorElem(LinkList *p,int i){

    LinkList t1 = (*p);
    LinkList t2 = (*p)->next;
    int len = (*p)->length;
    int k;
    if(len<1) return 0xffffffff;
    if((i<1)||(i>len)) return 0xffffffff;
    for(k = 1 ; k < i ; k++){
        t2 = t2->next;
        t1 = t1->next;
    }
    if(t1==(*p)) return 0xffffffff;
    return t1->data;

}

Datatype NextElem(LinkList *p,int i){

    int k;
    int len = (*p)->length;
    LinkList t = (*p)->next;
    if(len<1) return 0xffffffff;
    if((i<1)||(i>len)) return 0xffffffff;
    for(k = 1 ; k < i ; k++){
        t = t->next;
    }
    t = t->next;
    if(t==NULL) return 0xffffffff;
    return t->data;

}

void PrintElem(LinkList *p){

    LinkList t = (*p)->next;
    int i = 1;
    printf("List Length:%d\nElements: \n",(*p)->length);
    while(t!=NULL){
        printf("No.%d:%d ",i,t->data);
        t = t->next;
        i++;
    }
    printf("\n");
}

int main(){
    LinkList MLlist;

    InitList(&MLlist);
    //printf("%d\n", &MLlist);
    //测试插入
    ListInsert(&MLlist,1,3);
    ListInsert(&MLlist,1,4);
    ListInsert(&MLlist,1,2);
    ListInsert(&MLlist,2,6);
    PrintElem(&MLlist);

    printf("%d \n",GetElem(&MLlist,2));
    printf("%d \n",PriorElem(&MLlist,2));
    printf("%d \n",PriorElem(&MLlist,1));
    
    printf("%d \n",NextElem(&MLlist,2));
    printf("%d \n",NextElem(&MLlist,4));

    //测试删除--索引
    ListDeleteOfIndex(&MLlist,2);
    PrintElem(&MLlist);
    ListDeleteOfIndex(&MLlist,1);
    PrintElem(&MLlist);
    
    // 测试非法删除
    if(!ListDeleteOfIndex(&MLlist,17))
        printf("Error!\n");
    if(!ListDeleteOfEle(&MLlist,37))
        printf("The element is not exist\n");

    //测试删除--值类型
    ListDeleteOfEle(&MLlist,4);
    PrintElem(&MLlist);
    ListDeleteOfEle(&MLlist,2);
    PrintElem(&MLlist);
    
    free(MLlist);
    system("pause");
    return 0;
}

完整代码:(在我的机器上运行无误,请自行测试)
在文章最后会给出两个不同的创建链表的方法:头插法和尾插法

#include<stdio.h>
#include<windows.h>
#define maxsize 100
typedef int Datatype;
typedef struct Lnode{
    Datatype data; //数据域
    struct Lnode* next; //指针域
    int length; //当前链表长度
}LNode,*LinkList;

void InitList(LinkList *p); //构造一个空线性表
bool ListInsert(LinkList *p,int x,Datatype e);//插入操作(插入到第几个位置--类似于头插法)
bool ListDeleteOfIndex(LinkList *p,int x);//删除操作(根据位置)
bool ListDeleteOfEle(LinkList *p,Datatype e);//删除操作(根据值)
Datatype GetElem(LinkList *p,int i);//返回L中第i个数据元素的值

bool DestroyList(LinkList *p);//销毁整个线性表
void ClearList(LinkList *p);//清空整个线性表
bool ListEmpty(LinkList *p);//判断是否为空表
int ListLength(LinkList *p);//返回线性表元素个数
int LocateElem(LinkList *p,Datatype d);//返回与e相等的元素的位置序号
Datatype PriorElem(LinkList *p,int i);//返回元素前驱
Datatype NextElem(LinkList *p,int i);//返回元素后驱
void PrintElem(LinkList *p);//打印所有元素

void CreateList_F(LinkList *p);//头插法创建链表
void CreateList_L(LinkList *p);//尾插法创建链表

void CreateList_F(LinkList *p){

}

void CreateList_L(LinkList *p){

}


bool DestroyList(LinkList *p){

    LinkList t1 = (*p)->next;
    LinkList t2;
    if(t1==NULL) {free(*p);return true;}
    t2 = t1->next;
    while(t2!=NULL){

        free(t1);
        (*p)->length--;
        t1 = t2;
        t2 = t2->next;
        printf("%d",(*p)->length--);
    }
    free(t1);
    free(*p);
    return true; 

}

void ClearList(LinkList *p){

    LinkList t = (*p);
    while(t!=NULL){
        t->data = 0;
        t = t->next;
    }

}

bool ListEmpty(LinkList *p){
    if((*p)->length)
        return false;
    return true;
}
int LocateElem(LinkList *p,Datatype d){

    LinkList t = (*p)->next;
    int i = 1;
    while (t!=NULL)
    {
        if(t->data==d)  return i;
        i++;
        t = t->next;
    }
    return 0xffffffff;

}
int ListLength(LinkList *p){
    return (*p)->length;
}
void InitList(LinkList *p){ //二级指针: P指向MLlist指针的地址

    *p = (LNode*)malloc(sizeof(LNode)); 
    //给MLlist所在分配内存空间  *p = MLlist 
    // 可用printf("%d\n",&(*p));检验

    if(!(*p)) exit(-1);         //分配失败退出
    
    (*p) -> next = NULL; 
    (*p) -> length = 0 ;
    //(*p)->data = 3; 
    //令此结点为空作为head结点           
    //给所在内存空间赋值
    //printf("%d\n", (*p)->data); 
    //free(*p);
}

bool ListInsert(LinkList *p,int i,Datatype e){

    int x;   
    int len = (*p)->length;
    LinkList t = (*p); // 标号:标记头节点为0
    
    if((i<1)||(i>len+1)) return false;

    for(x = 1 ; x < i ; x++)
        t = t->next;
    
    LNode* L = (LNode*)malloc(sizeof(LNode));

    L->next = t->next;
    L->data = e;
    t->next = L;
    (*p)->length++;

    return true;

}

bool ListDeleteOfIndex(LinkList *p,int x){

    LinkList t1 = (*p);
    LinkList t2 = (*p)->next; //寻找所在结点
    int len = (*p)->length;
    int i;
    
    if((x<1)||(x>len)) return false;

    for(i = 1 ; i < x ; i++){  
        t1 = t1->next;
        t2 = t2->next;
    }

    t1->next = t2->next;
    (*p)->length--;
    free(t2);
    return true;

}

bool ListDeleteOfEle(LinkList *p,Datatype e){

    LinkList t1 = (*p);
    LinkList t2 = (*p)->next; //寻找所在结点
    
    while(true){
        if(t2==NULL)
            return false;    
        if(t2->data==e){
            break;
        }
        t1 = t1 -> next;
        t2 = t2 -> next;  
    }

    t1->next = t2->next;
    (*p)->length--;    
    free(t2);
    return true;

}

Datatype GetElem(LinkList *p,int i){

    LinkList t = (*p)->next;
    int len = (*p)->length;
    int k;
    if((i<1)||(i>len)) return 0xffffffff;
    for(k = 1; k < i; k++){
        t = t->next;
    }
    return t->data;

}

Datatype PriorElem(LinkList *p,int i){

    LinkList t1 = (*p);
    LinkList t2 = (*p)->next;
    int len = (*p)->length;
    int k;
    if(len<1) return 0xffffffff;
    if((i<1)||(i>len)) return 0xffffffff;
    for(k = 1 ; k < i ; k++){
        t2 = t2->next;
        t1 = t1->next;
    }
    if(t1==(*p)) return 0xffffffff;
    return t1->data;

}

Datatype NextElem(LinkList *p,int i){

    int k;
    int len = (*p)->length;
    LinkList t = (*p)->next;
    if(len<1) return 0xffffffff;
    if((i<1)||(i>len)) return 0xffffffff;
    for(k = 1 ; k < i ; k++){
        t = t->next;
    }
    t = t->next;
    if(t==NULL) return 0xffffffff;
    return t->data;

}

void PrintElem(LinkList *p){

    LinkList t = (*p)->next;
    int i = 1;
    printf("List Length:%d\nElements: \n",(*p)->length);
    while(t!=NULL){
        printf("No.%d:%d ",i,t->data);
        t = t->next;
        i++;
    }
    printf("\n");
}

int main(){
    
    system("pause");
    return 0;
}

3.头插法与尾插法创建链表(重点!与后续栈和队列联系紧密)

void CreateList_F(LinkList *p){
    Datatype temp;
    LinkList t;
    (*p) = (LNode*)malloc(sizeof(LNode));
    t = (*p);
    /*
    Thinking:
        为什么 LinkList t = *p;
              t = (LNode*)malloc(sizeof(LNode));
              这种写法会导致其他功能函数无法使用
        why?
    */

    if(!t) exit(-1);         //分配失败退出
    t -> next = NULL; 
    t -> length = 0 ;
    printf("Please input data:\n");
    while(scanf("%d",&temp)!=EOF){
        LNode* L = (LNode*)malloc(sizeof(LNode));
        L->data = temp;
        t->length++;
        //头插法   
        L->next = t->next;
        t->next = L;
    
    }

}

void CreateList_L(LinkList *p){
    Datatype temp;
    LinkList t;
    (*p) = (LNode*)malloc(sizeof(LNode));
    t = (*p);
    
    if(!t) exit(-1);         //分配失败退出
    t -> next = NULL; 
    t -> length = 0 ;
    
    printf("Please input data:\n");
    
    while(scanf("%d",&temp)!=EOF){
        LNode* L = (LNode*)malloc(sizeof(LNode));
        
        L->data = temp;
        t->length++;

        //尾插法
        L->next = NULL; 
        t->next = L;
        t = L;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值