前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【数据结构】线性表代码实现:顺序存储结构 | 链式存储结构

【数据结构】线性表代码实现:顺序存储结构 | 链式存储结构

作者头像
CtrlX
发布2023-03-21 11:52:47
1.5K0
发布2023-03-21 11:52:47
举报
文章被收录于专栏:C++核心编程

目录

  • 线性表
    • 顺序存储结构
      • 数组
    • 链式存储结构(有无头节点)
      • 单链表
      • 静态链表
      • 循环链表
        • 双向循环链表
        • 单向循环链表
      • 双向链表

顺序存储结构

数组

代码语言:javascript
复制
#include<stdio.h>
#include<stdlib.h>
//顺序表 数组
typedef struct ArrayList {
    int* list;//数组的堆区地址
    int count;//记录当前元素个数
    //因为数组的长度固定,所以还需要一个总容量
    int maxSize;//总容量
}List;

List* initList();
void insert(int key,List* list);
int find(List* list, int key);
void insert_index(int key, List* list, int date);
void printfList(List* list);
void delete_list(int key,List* list);

//初始化
List* initList() {
    List* list = (List*)malloc(sizeof(List));
    list->count = 0;
    list->maxSize = 5;
    list->list = (int*)malloc(sizeof(int) * 5);
    return list;
}

//查找
/*
关键:找到要查找元素的下标:为了方便所有元素向后移动一位
*/
int find(List* list, int key) {
    for (int i = 0; i < list->count; i++) {
        if (list->list[i] == key) return i;
    }
    return -1;
}

//插入:按照顺序插入
void insert(int key,List* list) {
    //首先判断当前元素的个数小于最大元素个数的时候可以插入
    if (list->count < list->maxSize) {
        list->list[list->count] = key;
        list->count++;
    }
    else {
        //提示满了或者直接扩容
        enlargement(list);
        list->list[list->count] = key;
        list->count++;
    }
}

//插入:在某个元素之前插入
/*
1.插入什么元素
2.在那个顺序表插入
3.在那个元素之前插入(要先查找是否有这个元素)
*/
void insert_index(int key, List* list, int date) {
    //先判断满没满
    if (list->count < list->maxSize) {
        //没满的话寻找下标
        int index = find(list, date);
        if (index == -1) {
            //没有这个元素,提示退出
            return;
        }
        else {
            //先移动
            for (int i = list->count; i < index; i--) {
                list->list[i] = list->list[i - 1];
            }
        }
        list->list[index] = key;
        list->count++;
    }
    else {
        //提示满了或者直接扩容
        enlargement(list);
        list->list[list->count] = key;
        list->count++;
    }
}

//输出表
void printfList(List* list) {
    for (int i = 0; i < list->count; i++) {
        printf("%d", list->list[i]);
    }
    printf("\n");
}

//删除
void delete_list(int key,List* list){
    //先考虑是否为空
    if(list->index == 0){
        //输入提示
    }
    else{
        int index = find(list,key);
        if(index == -1){
            //没有数据提示,无法删除
        }
        else{
            //删除操作就是单纯的移动,从index开始从右往左移动。逻辑删除。
            for(int i = index;i < list->count;i++){
                list->list[i] = list->list[i+1];
            }
            list->count--;
        }
    }
}

//扩容数组
/*
注意有扩容就要有在删除操作中添加缩容操作
*/
void enlargement(List* list){
    //每次扩容扩大5个
    int* temp = (int*)malloc(sizeof(int)*(list->maxSize +5));
    //首先要先将原来的数据拷贝到新的数组里面
    for(int i = 0;i < list->maxSize;i++){
        temp[i] = list->list[i];
        //先要定义个指针指向当前的数组地址,防止替换地址后找不到原来的内存地址,无法释放内存
        int*arrytemp = list->list;
        //然后在把List结构体中的指针替换成新扩容后的地址
        list->list = temp;
        list->maxSize += 5;
        //释放掉原来的内存
        free(arrytemp);
    }
}

int main() {
    List* list = initList();
    insert(1, list);
    insert(2, list);
    insert(3, list);
    insert(4, list);
    printfList(list);
    insert_index(5,list,3);
    printfList(list);
    delete_list(5,list);
    printfList(list);
    
}

链式存储结构

带头节点的单向链表

代码语言:javascript
复制
#include<stdio.h>
#include<stdlib.h>
//带 头节点 的单向链表

//数据集合 节点(抽象的类型)
typedef struct NodeList {
    int element;//存储具体的数据,可以是任意的类型,此处也可以是结构体类型
    struct NodeList* next;//用来指向下一个节点的指针
}Node;//别名

//操作集合
//初始化一个节点
Node* InitList(Node* node) {
    node = (Node*)malloc(sizeof(Node));
    //严谨一点的话malloc之后要判断malloc是否成功
    if (node == NULL) {
        //给用户一个提示内存分配失败,初始化失败
    }
    //malloc之后就有一个节点了,第一步要初始化里面的指针,让他们的地=地址指向NULL
    else node->next = NULL;
    return node;
}

//查找
/*
参数:
1.查找的具体数据是什么
2.往那个单链表里面查找
PS:返回类型也可以是指针
*/
int find(Node* node, int key) {
    //传入头节点
    //注意不能那头节点去找,头节点的作用是确定第一个元素的位置,需要先定义一个temp
    Node* temp;
    temp = node->next;//让temp指向第一个元素
    int i = 0;//用来指明删除的是第几个元素
    //下面开始去找
    while (temp != NULL) {
        if (temp->element == key) {
            return i;//找到就返回
        }
        temp = temp->next;
        i++;
    }
    return -1;//找不到返回-1
}

//单链表插入:头插法(往前插入)
/*
参数:
1.插入的具体数据是什么
2.往那个单链表里面插入
*/
void head_insert(Node* node, int key) {
    //插入一个新的节点还是malloc创建一个新的节点
    Node* temp = (Node*)malloc(sizeof(Node));
    //注意头插的话头节点是固定的
    //1.新节点的下一个指针指向头街点的下一个指针
    temp->next = node->next;
    //2,头节点的指针指向新的节点
    node->next = temp;
    //3,插入的元素赋值
    temp->element = key;
}

//单链表插入:中间节点插入
/*
参数:
1.插入的具体数据是什么
2.往那个单链表里面插入
关键:
涉及到了查找的问题(插入不一定要查找,具体问题具体分析)
*/
void ListnIsert(Node* node, int i, int key) {
    //初始化一个指针指向链表的头节点
    int j = 1;
    Node *p = node;
    //当j<i时就遍历链表,让p的指针向后移动,不断指向下一个节点
    while (p && j < i) {
        p = p->next;
        j++;
    }
    //如果到链表的末尾p为空,测说明第i个元素节点不存在
    if ( !p || j > i) {
        //给用户提示报错
    }
    //如果查找成功,在系统中生成一个空节点
    //插入一个新的节点还是malloc创建一个新的节点
    Node* temp = (Node*)malloc(sizeof(Node));
    //注意头插的话头节点是固定的
    //1.新节点的下一个指针指向头街点的下一个指针
    temp->next = node->next;
    //2,头节点的指针指向新的节点
    node->next = temp;
    //3,插入的元素赋值
    temp->element = key;


}

//单链表删除
/*
参数:
1.删除的具体数据是什么
2.往那个单链表里面删除
关键:
涉及到了查找的问题
如何定位:定位到待删除元素的前一个元素比较好
*/
void Delete(Node* node, int key) {
    //先查找是否有该元素
    int index = find(node, key);
    if (index == -1)//若find函数使用的是指针就把-1改NULL
    {
        //没找到 提示一下
    }
    else {
        Node* temp;
        temp = node;
        int i = 0;
        while (i < index)//若这里定位到第一个元素(node->next)则就改为i < index -1
        {
            temp = temp->next;
            i++;
        }
        //注意要先行医一个指针指向待删除的元素,不然执行完后面的指针替换的操作后就找不到这个待删除的元素了,就无法释放它的内存了
        Node* free_node = temp->next;
        //逻辑上进行删除
        temp->next = temp->next->next;
        //释放要删除的节点的空间
        free(free_node);
    }
}

int main() {

}

单链表插入:头插法(往前插入)void head_insert(Node*node,int key)

单链表删除void delete(Node*node,int key)

要删除3最好定位到2,为了方便执行temp->next = temp->next->next;将2指向4

注意删除前要保存下3的地址,方便执行释放内存的指令

问题:在插入时如果插入了重复的元素怎么办?

思考一:是否允许这个数据存在,怎么处理这个重复的数据?具体根据实际的业务。

思考二:加入允许,这个重复的数据时要插入到哪里?是插入到这个重复数据相同数据的旁边,还是插入到后面?

如果是按照顺序插入到所有数据的后面,则按照正常的中间插入函数插入即可。

如果是插入到与这个元素相同的值的旁边则没有必要运行插入函数,只需要再定义一个数据,记录重复数据。

代码语言:javascript
复制
//数据集合 节点(抽象的类型)
typedef struct NodeList{
    int element;//存储具体的数据,可以是任意的类型,此处也可以是结构体类型
    struct NodeList *next;//用来指向下一个节点的指针
    int count;//记录重复数据的个数
}Node;//别名

即若有重复的数据只需要让count++即可,只需要在输出的时候判断一下这个数字就行,这个是数字有几个就用for循环打印几个。

带头节点的双向循环链表

代码语言:javascript
复制
#include<stdio.h>
#include<stdlib.h>

typedef struct DoubleList{
    struct DoubleList* front;
    int element;//数据域
    struct DoubleList* next;
}List;

//初始化
List* head;//当好多个方法都要用到这个的时候我们就可以把它放到全局或者是静态的全局,这样的话在函数中就不需要传参去使用了,可以直接用,但是注意:用的时候要拷贝,不要直接去动它!
void initList(){
    head = (List*)malloc(sizeof(List));
    //既然是循环的,则指向自己
    head->next = head;
    head->front = head;
}

//插入:头插
void head_insert(int key){
    //新建一个节点
    List* new_node = (List*)malloc(sizeof(List));
    //先把数据写进去
    new_node->element = key;
    //更改节点指针
    new_node->next = head->next;
    new_node->front = head;
    head->next->front = new_node;
    head->next->next = new_node;
}

//查询
int find(int key){
    List* temp = head->next;
    int i = 0;
    while(temp != head){
        if(temp->element ==key){
            return i;
        }
        i++;
        temp = temp->next;
    }
    return -1;
}

//删除、
void delet_node(int key){
    //既然要删除元素,要先判断是否为空
    if(head == NULL){
        //无法删除
    }
    else{
        int index = find(key);
        if(index == -1){
            //没有数据提示,无法删除
        }
        else{
            List* temp = head;
            int i = 0;
            while(i<index){
                temp = temp->next;
                i++;
            }
            List* free_node = temp->next;
            temp->next->next->front = temp;
            temp->next = temp->next->next;
            free(free_node);
        }
    }
}

插入:头插void head_insert(int key)

PS:缩容问题

思路:用一个判断:假设扩容时是5,用数组的容量减去当前数组中数据的个数,如果大于5就缩容。

代码语言:javascript
复制

线性表

线性表顺序存储_List.c

代码语言:javascript
复制
#include "stdio.h"    

#include "stdlib.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20          /* 存储空间初始分配量 */
typedef int ElemType;       /* ElemType类型根据实际情况而定,这里假设为int */
typedef struct
{
    ElemType data[MAXSIZE]; /* 数组,存储数据元素 */
    int length;             /* 线性表当前长度 */
}SqList;

typedef int Status;         /* Status是函数的类型,其值是函数结果状态代码,如OK等 */


Status visit(ElemType c)
{
    printf("%d ",c);
    return OK;
}

/* 初始化顺序线性表 */
Status InitList(SqList *L) 
{ 
    L->length=0;
    return OK;
}

/* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(SqList L)
{ 
	if(L.length==0)
		return TRUE;
	else
		return FALSE;
}

/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(SqList *L)
{ 
    L->length=0;
    return OK;
}

/* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(SqList L)
{
	return L.length;
}

/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值,注意i是指位置,第1个位置的数组是从0开始 */
Status GetElem(SqList L,int i,ElemType *e)
{
    if(L.length==0 || i<1 || i>L.length)
            return ERROR;
    *e=L.data[i-1];

    return OK;
}

/* 初始条件:顺序线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(SqList L,ElemType e)
{
    int i;
    if (L.length==0)
            return 0;
    for(i=0;i<L.length;i++)
    {
            if (L.data[i]==e)
                    break;
    }
    if(i>=L.length)
            return 0;

    return i+1;
}


/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(SqList *L,int i,ElemType e)
{ 
	int k;
	if (L->length==MAXSIZE)  /* 顺序线性表已经满 */
		return ERROR;
	if (i<1 || i>L->length+1)/* 当i比第一位置小或者比最后一位置后一位置还要大时 */
		return ERROR;

	if (i<=L->length)        /* 若插入数据位置不在表尾 */
	{
		for(k=L->length-1;k>=i-1;k--)  /* 将要插入位置之后的数据元素向后移动一位 */
			L->data[k+1]=L->data[k];
	}
	L->data[i-1]=e;          /* 将新元素插入 */
	L->length++;

	return OK;
}

/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(SqList *L,int i,ElemType *e) 
{ 
    int k;
    if (L->length==0)               /* 线性表为空 */
		return ERROR;
    if (i<1 || i>L->length)         /* 删除位置不正确 */
        return ERROR;
    *e=L->data[i-1];
    if (i<L->length)                /* 如果删除不是最后位置 */
    {
        for(k=i;k<L->length;k++)/* 将删除位置后继元素前移 */
			L->data[k-1]=L->data[k];
    }
    L->length--;
    return OK;
}

/* 初始条件:顺序线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(SqList L)
{
	int i;
    for(i=0;i<L.length;i++)
            visit(L.data[i]);
    printf("\n");
    return OK;
}

/*将所有的在线性表Lb中但不在La中的数据元素插入到La中*/
void unionL(SqList *La,SqList Lb)
{
	int La_len,Lb_len,i;
	ElemType e;                        /*声明与La和Lb相同的数据元素e*/
	La_len=ListLength(*La);            /*求线性表的长度 */
	Lb_len=ListLength(Lb);
	for (i=1;i<=Lb_len;i++)
	{
		GetElem(Lb,i,&e);              /*取Lb中第i个数据元素赋给e*/
		if (!LocateElem(*La,e))        /*La中不存在和e相同数据元素*/
			ListInsert(La,++La_len,e); /*插入*/
	}
}

int main()
{
        
    SqList L;
	SqList Lb;
    
    ElemType e;
    Status i;
    int j,k;
    i=InitList(&L);
    printf("初始化L后:L.length=%d\n",L.length);
    for(j=1;j<=5;j++)
            i=ListInsert(&L,1,j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L); 

    printf("L.length=%d \n",L.length);
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    i=ClearList(&L);
    printf("清空L后:L.length=%d\n",L.length);
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L); 

    printf("L.length=%d \n",L.length);

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("L.length=%d \n",L.length);

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    

    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

	//构造一个有10个数的Lb
	i=InitList(&Lb);
    for(j=6;j<=15;j++)
            i=ListInsert(&Lb,1,j);

	unionL(&L,Lb);

	printf("依次输出合并了Lb的L的元素:");
    ListTraverse(L); 

    return 0;
}

线性表链式存储结构_LinkList.c

代码语言:javascript
复制
#include "stdio.h"    
#include "string.h"
#include "ctype.h"      
#include "stdlib.h"   

#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */


Status visit(ElemType c)
{
    printf("%d ",c);
    return OK;
}

typedef struct Node
{
    ElemType data;
    struct Node *next;
}Node;
typedef struct Node *LinkList; /* 定义LinkList */

/* 初始化链式线性表 */
Status InitList(LinkList *L) 
{ 
    *L=(LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
    if(!(*L)) /* 存储分配失败 */
            return ERROR;
    (*L)->next=NULL; /* 指针域为空 */

    return OK;
}

/* 初始条件:链式线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{ 
    if(L->next)
            return FALSE;
    else
            return TRUE;
}

/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(LinkList *L)
{ 
	LinkList p,q;
	p=(*L)->next;           /*  p指向第一个结点 */
	while(p)                /*  没到表尾 */
	{
		q=p->next;
		free(p);
		p=q;
	}
	(*L)->next=NULL;        /* 头结点指针域为空 */
	return OK;
}

/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
    int i=0;
    LinkList p=L->next; /* p指向第一个结点 */
    while(p)                        
    {
        i++;
        p=p->next;
    }
    return i;
}

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
	int j;
	LinkList p;		/* 声明一结点p */
	p = L->next;		/* 让p指向链表L的第一个结点 */
	j = 1;		/*  j为计数器 */
	while (p && j<i)  /* p不为空或者计数器j还没有等于i时,循环继续 */
	{   
		p = p->next;  /* 让p指向下一个结点 */
		++j;
	}
	if ( !p || j>i ) 
		return ERROR;  /*  第i个元素不存在 */
	*e = p->data;   /*  取第i个元素的数据 */
	return OK;
}

/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(LinkList L,ElemType e)
{
    int i=0;
    LinkList p=L->next;
    while(p)
    {
        i++;
        if(p->data==e) /* 找到这样的数据元素 */
                return i;
        p=p->next;
    }

    return 0;
}


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{ 
	int j;
	LinkList p,s;
	p = *L;   
	j = 1;
	while (p && j < i)     /* 寻找第i个结点 */
	{
		p = p->next;
		++j;
	} 
	if (!p || j > i) 
		return ERROR;   /* 第i个元素不存在 */
	s = (LinkList)malloc(sizeof(Node));  /*  生成新结点(C语言标准函数) */
	s->data = e;  
	s->next = p->next;      /* 将p的后继结点赋值给s的后继  */
	p->next = s;          /* 将s赋值给p的后继 */
	return OK;
}

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList *L,int i,ElemType *e) 
{ 
	int j;
	LinkList p,q;
	p = *L;
	j = 1;
	while (p->next && j < i)	/* 遍历寻找第i个元素 */
	{
        p = p->next;
        ++j;
	}
	if (!(p->next) || j > i) 
	    return ERROR;           /* 第i个元素不存在 */
	q = p->next;
	p->next = q->next;			/* 将q的后继赋值给p的后继 */
	*e = q->data;               /* 将q结点中的数据给e */
	free(q);                    /* 让系统回收此结点,释放内存 */
	return OK;
}

/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(LinkList L)
{
    LinkList p=L->next;
    while(p)
    {
        visit(p->data);
        p=p->next;
    }
    printf("\n");
    return OK;
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateListHead(LinkList *L, int n) 
{
	LinkList p;
	int i;
	srand(time(0));                         /* 初始化随机数种子 */
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL;                      /*  先建立一个带头结点的单链表 */
	for (i=0; i<n; i++) 
	{
		p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
		p->data = rand()%100+1;             /*  随机生成100以内的数字 */
		p->next = (*L)->next;    
		(*L)->next = p;						/*  插入到表头 */
	}
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail(LinkList *L, int n) 
{
	LinkList p,r;
	int i;
	srand(time(0));                      /* 初始化随机数种子 */
	*L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
	r=*L;                                /* r为指向尾部的结点 */
	for (i=0; i<n; i++) 
	{
		p = (Node *)malloc(sizeof(Node)); /*  生成新结点 */
		p->data = rand()%100+1;           /*  随机生成100以内的数字 */
		r->next=p;                        /* 将表尾终端结点的指针指向新结点 */
		r = p;                            /* 将当前的新结点定义为表尾终端结点 */
	}
	r->next = NULL;                       /* 表示当前链表结束 */
}

int main()
{        
    LinkList L;
    ElemType e;
    Status i;
    int j,k;
    i=InitList(&L);
    printf("初始化L后:ListLength(L)=%d\n",ListLength(L));
    for(j=1;j<=5;j++)
            i=ListInsert(&L,1,j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L); 

    printf("ListLength(L)=%d \n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    i=ClearList(&L);
    printf("清空L后:ListLength(L)=%d\n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L); 

    printf("ListLength(L)=%d \n",ListLength(L));

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    

    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

    i=ClearList(&L);
    printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));
    CreateListHead(&L,20);
    printf("整体创建L的元素(头插法):");
    ListTraverse(L); 
    
    i=ClearList(&L);
    printf("\n删除L后:ListLength(L)=%d\n",ListLength(L));
    CreateListTail(&L,20);
    printf("整体创建L的元素(尾插法):");
    ListTraverse(L); 


    return 0;
}

静态链表_StaticLinkList.c

代码语言:javascript
复制
#include "stdio.h"    
#include "string.h"
#include "ctype.h"      
#include "stdlib.h"   

#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */


Status visit(ElemType c)
{
    printf("%d ",c);
    return OK;
}

typedef struct Node
{
    ElemType data;
    struct Node *next;
}Node;
typedef struct Node *LinkList; /* 定义LinkList */

/* 初始化链式线性表 */
Status InitList(LinkList *L) 
{ 
    *L=(LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
    if(!(*L)) /* 存储分配失败 */
            return ERROR;
    (*L)->next=NULL; /* 指针域为空 */

    return OK;
}

/* 初始条件:链式线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{ 
    if(L->next)
            return FALSE;
    else
            return TRUE;
}

/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(LinkList *L)
{ 
	LinkList p,q;
	p=(*L)->next;           /*  p指向第一个结点 */
	while(p)                /*  没到表尾 */
	{
		q=p->next;
		free(p);
		p=q;
	}
	(*L)->next=NULL;        /* 头结点指针域为空 */
	return OK;
}

/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
    int i=0;
    LinkList p=L->next; /* p指向第一个结点 */
    while(p)                        
    {
        i++;
        p=p->next;
    }
    return i;
}

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
	int j;
	LinkList p;		/* 声明一结点p */
	p = L->next;		/* 让p指向链表L的第一个结点 */
	j = 1;		/*  j为计数器 */
	while (p && j<i)  /* p不为空或者计数器j还没有等于i时,循环继续 */
	{   
		p = p->next;  /* 让p指向下一个结点 */
		++j;
	}
	if ( !p || j>i ) 
		return ERROR;  /*  第i个元素不存在 */
	*e = p->data;   /*  取第i个元素的数据 */
	return OK;
}

/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(LinkList L,ElemType e)
{
    int i=0;
    LinkList p=L->next;
    while(p)
    {
        i++;
        if(p->data==e) /* 找到这样的数据元素 */
                return i;
        p=p->next;
    }

    return 0;
}


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{ 
	int j;
	LinkList p,s;
	p = *L;   
	j = 1;
	while (p && j < i)     /* 寻找第i个结点 */
	{
		p = p->next;
		++j;
	} 
	if (!p || j > i) 
		return ERROR;   /* 第i个元素不存在 */
	s = (LinkList)malloc(sizeof(Node));  /*  生成新结点(C语言标准函数) */
	s->data = e;  
	s->next = p->next;      /* 将p的后继结点赋值给s的后继  */
	p->next = s;          /* 将s赋值给p的后继 */
	return OK;
}

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList *L,int i,ElemType *e) 
{ 
	int j;
	LinkList p,q;
	p = *L;
	j = 1;
	while (p->next && j < i)	/* 遍历寻找第i个元素 */
	{
        p = p->next;
        ++j;
	}
	if (!(p->next) || j > i) 
	    return ERROR;           /* 第i个元素不存在 */
	q = p->next;
	p->next = q->next;			/* 将q的后继赋值给p的后继 */
	*e = q->data;               /* 将q结点中的数据给e */
	free(q);                    /* 让系统回收此结点,释放内存 */
	return OK;
}

/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(LinkList L)
{
    LinkList p=L->next;
    while(p)
    {
        visit(p->data);
        p=p->next;
    }
    printf("\n");
    return OK;
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateListHead(LinkList *L, int n) 
{
	LinkList p;
	int i;
	srand(time(0));                         /* 初始化随机数种子 */
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL;                      /*  先建立一个带头结点的单链表 */
	for (i=0; i<n; i++) 
	{
		p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
		p->data = rand()%100+1;             /*  随机生成100以内的数字 */
		p->next = (*L)->next;    
		(*L)->next = p;						/*  插入到表头 */
	}
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail(LinkList *L, int n) 
{
	LinkList p,r;
	int i;
	srand(time(0));                      /* 初始化随机数种子 */
	*L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
	r=*L;                                /* r为指向尾部的结点 */
	for (i=0; i<n; i++) 
	{
		p = (Node *)malloc(sizeof(Node)); /*  生成新结点 */
		p->data = rand()%100+1;           /*  随机生成100以内的数字 */
		r->next=p;                        /* 将表尾终端结点的指针指向新结点 */
		r = p;                            /* 将当前的新结点定义为表尾终端结点 */
	}
	r->next = NULL;                       /* 表示当前链表结束 */
}

int main()
{        
    LinkList L;
    ElemType e;
    Status i;
    int j,k;
    i=InitList(&L);
    printf("初始化L后:ListLength(L)=%d\n",ListLength(L));
    for(j=1;j<=5;j++)
            i=ListInsert(&L,1,j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L); 

    printf("ListLength(L)=%d \n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    i=ClearList(&L);
    printf("清空L后:ListLength(L)=%d\n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L); 

    printf("ListLength(L)=%d \n",ListLength(L));

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    

    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

    i=ClearList(&L);
    printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));
    CreateListHead(&L,20);
    printf("整体创建L的元素(头插法):");
    ListTraverse(L); 
    
    i=ClearList(&L);
    printf("\n删除L后:ListLength(L)=%d\n",ListLength(L));
    CreateListTail(&L,20);
    printf("整体创建L的元素(尾插法):");
    ListTraverse(L); 


    return 0;
}

课程代码.c

代码语言:javascript
复制
Status ListInsert(StaticLinkList L, int i, ElemType e)   
{  
	int j, k, l;   
	k = MAXSIZE - 1;   					/* 注意k首先是最后一个元素的下标 */
	if (i < 1 || i > ListLength(L) + 1)   
		return ERROR;   
	j = Malloc_SSL(L);   				/* 获得空闲分量的下标 */
	if (j)   
	{   
		L[j].data = e;   				/* 将数据赋值给此分量的data */
		for(l = 1; l <= i - 1; l++)   	/* 找到第i个元素之前的位置 */
		   k = L[k].cur;           
		L[j].cur = L[k].cur;    		/* 把第i个元素之前的cur赋值给新元素的cur */
		L[k].cur = j;           		/* 把新元素的下标赋值给第i个元素之前元素的ur */
		return OK;   
	}   
	return ERROR;   
}

/*将所有的在线性表Lb中但不在La中的数据元素插入到La中*/
void unionL(SqList *La,SqList Lb)
{
	int La_len,Lb_len,i;
	ElemType e;                        /*声明与La和Lb相同的数据元素e*/
	La_len=ListLength(*La);            /*求线性表的长度 */
	Lb_len=ListLength(Lb);
	for (i=1;i<=Lb_len;i++)
	{
		GetElem(Lb,i,&e);              /*取Lb中第i个数据元素赋给e*/
		if (!LocateElem(*La,e))        /*La中不存在和e相同数据元素*/
			ListInsert(La,++La_len,e); /*插入*/
	}
}



#define MAXSIZE 20          /* 存储空间初始分配量 */
typedef int ElemType;       /* ElemType类型根据实际情况而定,这里为int */
typedef struct
{
	ElemType data[MAXSIZE]; /* 数组,存储数据元素 */
	int length;             /* 线性表当前长度 */
}SqList;


#define OK 1
#define ERROR 0
/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Status;         

/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值,注意i是指位置,第1个位置的数组是从0开始 */
Status GetElem(SqList L,int i,ElemType *e)
{
	if(L.length==0 || i<1 || i>L.length)
		return ERROR;
	*e=L.data[i-1];

	return OK;
}

/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(SqList *L,int i,ElemType e)
{ 
	int k;
	if (L->length==MAXSIZE)  			/* 顺序线性表已经满 */
		return ERROR;
	if (i<1 || i>L->length+1)			/* 当i比第一位置小或者比最后一位置后一位置还要大时 */
		return ERROR;				

	if (i<=L->length)        			/* 若插入数据位置不在表尾 */
	{
		for(k=L->length-1;k>=i-1;k--)  	/* 将要插入位置后的元素向后移一位 */
			L->data[k+1]=L->data[k];
	}
	L->data[i-1]=e;          			/* 将新元素插入 */
	L->length++;

	return OK;
}


/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(SqList *L,int i,ElemType *e) 
{ 
	int k;
	if (L->length==0)               /* 线性表为空 */
		return ERROR;
	if (i<1 || i>L->length)         /* 删除位置不正确 */
		return ERROR;
	*e=L->data[i-1];
	if (i<L->length)                /* 如果删除不是最后位置 */
	{
		for(k=i;k<L->length;k++)	/* 将删除位置后继元素前移 */
			L->data[k-1]=L->data[k];
	}
	L->length--;
	return OK;
}

/* 线性表的单链表存储结构 */
typedef struct Node
{
	ElemType data;
	struct Node *next;
}Node;
typedef struct Node *LinkList; /* 定义LinkList */


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
	int j;
	LinkList p;		/* 声明一结点p */
	p = L->next;		/* 让p指向链表L的第一个结点 */
	j = 1;		/*  j为计数器 */
	while (p && j<i)  /* p不为空或者计数器j还没有等于i时,循环继续 */
	{   
		p = p->next;  /* 让p指向下一个结点 */
		++j;
	}
	if ( !p || j>i ) 
		return ERROR;  /*  第i个元素不存在 */
	*e = p->data;   /*  取第i个元素的数据 */
	return OK;
}


s->next = p->next;    /* 将p的后继结点赋值给s的后继  */
p->next = s;          /* 将s赋值给p的后继 */


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{ 
	int j;
	LinkList p,s;
	p = *L;   
	j = 1;
	while (p && j < i)     				/* 寻找第i个结点 */
	{
		p = p->next;
		++j;
	} 
	if (!p || j > i) 
		return ERROR;   				/* 第i个元素不存在 */

	s = (LinkList)malloc(sizeof(Node)); /* 生成新结点(C语言标准函数) */
	s->data = e;  
	s->next = p->next;    				/* 将p的后继结点赋值给s的后继 */
	p->next = s;          				/* 将s赋值给p的后继 */
	return OK;
}

q = p->next;
p->next = q->next;			/* 将q的后继赋值给p的后继 */


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList *L,int i,ElemType *e) 
{ 
	int j;
	LinkList p,q;
	p = *L;
	j = 1;
	while (p->next && j < i)	/* 遍历寻找第i个元素 */
	{
		p = p->next;
		++j;
	}
	if (!(p->next) || j > i) 
		return ERROR;           /* 第i个元素不存在 */
	q = p->next;
	p->next = q->next;			/* 将q的后继赋值给p的后继 */
	*e = q->data;               /* 将q结点中的数据给e */
	free(q);                    /* 让系统回收此结点,释放内存 */
	return OK;
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateListHead(LinkList *L, int n) 
{
	LinkList p;
	int i;
	srand(time(0));                         /* 初始化随机数种子 */
	*L = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL;                      /* 先建立一个带头结点的单链表 */
	for (i=0; i<n; i++) 
	{
		p = (LinkList)malloc(sizeof(Node)); /* 生成新结点 */
		p->data = rand()%100+1;             /* 随机生成100以内的数字 */
		p->next = (*L)->next;    
		(*L)->next = p;						/* 插入到表头 */
	}
}

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail(LinkList *L, int n) 
{
	LinkList p,r;
	int i;
	srand(time(0));                     	/* 初始化随机数种子 */
	*L = (LinkList)malloc(sizeof(Node)); 	/* L为整个线性表 */
	r=*L;                                	/* r为指向尾部的结点 */
	for (i=0; i<n; i++) 
	{
		p = (Node *)malloc(sizeof(Node)); 	/* 生成新结点 */
		p->data = rand()%100+1;           	/* 随机生成100以内的数字 */
		r->next=p;                        	/* 将表尾终端结点的指针指向新结点 */
		r = p;                            	/* 将当前的新结点定义为表尾终端结点 */
	}
	r->next = NULL;                       	/* 表示当前链表结束 */
}


/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(LinkList *L)
{ 
	LinkList p,q;
	p=(*L)->next;           /*  p指向第一个结点 */
	while(p)                /*  没到表尾 */
	{
		q=p->next;
		free(p);
		p=q;
	}
	(*L)->next=NULL;        /* 头结点指针域为空 */
	return OK;
}


#define MAXSIZE 1000 	/* 存储空间初始分配量 */

/* 线性表的静态链表存储结构 */
typedef struct 
{
	ElemType data;
	int cur;  			/* 游标(Cursor) ,为0时表示无指向 */
} Component,StaticLinkList[MAXSIZE];



/* 将一维数组space中各分量链成一个备用链表,space[0].cur为头指针,"0"表示空指针 */
Status InitList(StaticLinkList space) 
{
	int i;
	for (i=0; i<MAXSIZE-1; i++)  
		space[i].cur = i+1;
	space[MAXSIZE-1].cur = 0; 	/* 目前静态链表为空,最后一个元素的cur为0 */
	return OK;
}

/* 若备用空间链表非空,则返回分配的结点下标,否则返回0 */
int Malloc_SSL(StaticLinkList space) 
{ 
	int i = space[0].cur;           		/* 当前数组第一个元素的cur存的值 */
											/* 就是要返回的第一个备用空闲的下标 */
	if (space[0]. cur)         
		space[0]. cur = space[i].cur;       /* 由于要拿出一个分量来使用了, */
											/* 所以我们就得把它的下一个 */
											/* 分量用来做备用 */
	return i;
}

/*  删除在L中第i个数据元素   */
Status ListDelete(StaticLinkList L, int i)   
{ 
	int j, k;   
	if (i < 1 || i > ListLength(L))   
		return ERROR;   
	k = MAXSIZE - 1;   
	for (j = 1; j <= i - 1; j++)   
		k = L[k].cur;   
	j = L[k].cur;   
	L[k].cur = L[j].cur;   
	Free_SSL(L, j);   
	return OK;   
} 

/*  将下标为k的空闲结点回收到备用链表 */
void Free_SSL(StaticLinkList space, int k) 
{  
	space[k].cur = space[0].cur;    /* 把第一个元素的cur值赋给要删除的分量cur */
	space[0].cur = k;               /* 把要删除的分量下标赋值给第一个元素的cur */
}

/* 初始条件:静态链表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(StaticLinkList L)
{
	int j=0;
	int i=L[MAXSIZE-1].cur;
	while(i)
	{
		i=L[i].cur;
		j++;
	}
	return j;
}

p=rearA->next;   			    /* 保存A表的头结点,即① */
rearA->next=rearB->next->next;	/* 将本是指向B表的第一个结点(不是头结点)*/
                 				/* 赋值给reaA->next,即② */
q=rearB->next;
rearB->next=p;				   	/* 将原A表的头结点赋值给rearB->next,即③ */
free(q);					   	/* 释放q */



/*线性表的双向链表存储结构*/
typedef struct DulNode
{
		ElemType data;
		struct DuLNode *prior;    	/*直接前驱指针*/
		struct DuLNode *next;		/*直接后继指针*/
} DulNode, *DuLinkList;


p->next->prior = p = p->prior->next

s - >prior = p;   			/*把p赋值给s的前驱,如图中①*/
s -> next = p -> next;		/*把p->next赋值给s的后继,如图中②*/
p -> next -> prior = s;		/*把s赋值给p->next的前驱,如图中③*/
p -> next = s;				/*把s赋值给p的后继,如图中④*/


p->prior->next=p->next;   	/*把p->next赋值给p->prior的后继,如图中①*/
p->next->prior=p->prior;	/*把p->prior赋值给p->next的前驱,如图中②*/
free(p);					/*释放结点*/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 顺序存储结构
    • 数组
    • 链式存储结构
      • 带头节点的单向链表
        • 带头节点的双向循环链表
          • PS:缩容问题
          • 线性表
            • 线性表顺序存储_List.c
              • 线性表链式存储结构_LinkList.c
                • 静态链表_StaticLinkList.c
                  • 课程代码.c
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档