【数据结构】线性表

1.1 顺序表

1.1.1顺序表的定义

采用顺序储存,用一组地址连续的存储单元存放数据元素。逻辑上相邻的数据元素,其物理位置也是相邻的。由于数组具有随机访问特性,所以通常用数组来描述顺序表。在C语言中,可用动态分配的一维数组表示顺序表。

// 顺序表的最大长度
#define MAXSIZE 100
​
// 表中数据元素的类型
typedef int ElemType;
​
// 定义顺序表类型
typedef struct {
  // 存储空间的基地址
  ElemType* elem;
  // 表中实际存储的数据元素个数(当前表的长度
  int length;
}SeqList;
1.1.2 初始化

使用malloc,为顺序表L动态分配一个预定义大小的数组空间,使elem指向这段空间的基地址。

Status InitList(SeqList &L) {
    // 为顺序表分配一个大小为MAXSIZE的数组空间
    L.elem=(ElemType *)malloc(sizeof(ElemType) * MAXSIZE);
    // 分配失败,退出
    if(!L.elem) exit(OVERFLOW);
    // 空表的长度为0
    L.length=0;
    
    return 1;
}
1.1.3 基本操作

1.插入

//在顺序表L的第i个位置插入新元素e
bool ListInsert(SqList &L,int i,ElemType e) {
	if(i<1||i>L.length+1){ //判断i的位置 
		return false;
	}
	if(L.length>=MaxSize){ //判断储存空间是否已满 
		return false;
	}
	for(int j=i-1;j<L.length;j++){
		L.data[j+1]=L.data[j];
	} 
	L.data[i-1]=e;
	L.length++;
	return true;
}

2.删除

//删除顺序表L中第i个位置的元素,并将被删除的元素用引用变量e返回
bool ListDelete (SqList &L,int i,ElemType &e){
	if(i<=1||i>L.length){
		return false;
    }
	e=L.data[i-1];
	for (int j=i;j<L.length;j++){
		L.data[j-1]=L.data[j];
    }
	L.length--;
	return true;
}

3.按值查找

//查找第一个元素值等于e的元素,并返回其位序
int LocalElem(SqList L,ElemType e){
	int i;
	for(i=0;i<L.length;i++)
		if(L.data[i]==e)
			return i+1;
	return 0;
}

以上三个操作的时间复杂度均为O(n)

1.2 链表

1.单链表及其操作

#include <stdio.h>
typedef struct node_
{
    int data;
    struct node_* next;
} Node;

//创建表头
Node* creatList()
{
    Node* head = (Node*)malloc(sizeof(Node));
    head->next = NULL;
    //返回表头地址
    return head;
}

//创建结点
Node* creatNode(int data)
{
    Node* newNode = (Node*)malloc(sizeof(Node));

    newNode->data = data;
    newNode->next = NULL;

    return newNode;
}

//头插法
void insertNodeByHead(Node* head, int data)
{
    //创建插入的节点,创建节点的同时对其数据域赋值
    Node* newNode = creatNode(data);
    newNode->next = head->next;//newNode—>next ==NULL
    head->next = newNode;
}
//尾插法
void insertNodeByTail(Node* head, int data)
{
    Node* newNode = creatNode(data);
    //找到表尾
    Node* tail = head;
    while (tail->next != NULL)
    {
        tail = tail->next;

    }
    tail->next = newNode;
}

//删除头结点
void deleteNodeByHead(Node* headNode)
{
    Node* deleteNode = headNode->next;
    headNode->next = deleteNode->next;
    free(deleteNode);
    deleteNode = NULL;
}

//删除尾结点
void deleteNodeByTail(Node* head)
{
    Node* tail = head;
    Node* tailFront = NULL;
    while (taile->next != NULL)
    {
        tailFront = tail;
        tail = tail->next;
    }
    free(tail);
    tail = NULL;
    tailFront->next = NULL;
}
//修改
void changeNode(Node* head, int changeData, int posData)
{
    Node* p = head->next;
    if (p == NULL)
    {
        printf("链表为空.\n");
        return;
    }
    else
    {
        while (p->data != posData)
        {
            p = p->next;
            if (p == NULL)
            {
                printf("没有找到该数据.\n");
                return;
            }
        }
        p->data = changeData;
    }
}

//查找
void findNode(Node* head, int findData)
{
    Node* p = head;
    printf("请输入您要查询的数据:\n");
    scanf("%d", &findData);
    if (p->next == NULL)
    {
        printf("链表为空!\n");
    }
    else
    {
        while (p->data != findData)
        {
            p = p->next;
            if (p->next == NULL)
            {
                printf("没有找到该数据!\n");
                return;
            }
        }
        printf("目标数据:%d存在于链表中!\n", p->data);
    }
}
//打印
void printList(Node* headNode)
{
    Node* p = headNode->next;
    while (p)
    {
        printf("%d\t", p->data);
        p = p->next;
    }
    printf("\n");
}


2.双链表及其操作
//结点类型
typedef struct DNode{
    int data;  //数据域
    struct DNode *pre,*next;  //前驱和后继指针
}DNode, *DLinkList;

//初始化
void InitList(DLinkList &L){
    L = (DNode *)malloc(sizeof(DLinkList));
    L->pre = NULL;
    L->next = NULL;
}

//头插法建立双链表,在头结点后插入新结点
DLinkList HeadInsert(DLinkList &L){
    InitList(L); //初始化
    int x;
    cin>>x;
    while(x!=9999){
        DNode *s = (DNode *)malloc(sizeof(DNode));
        s->data = x;
        if(L->next == NULL){
            s->next = NULL;
            s->pre = L;
            L->next = s;
        }else{
            s->next = L->next;
            L->next->pre = s;
            s->pre = L;
            L->next = s;
        }
        cin>>x;
    }
    return L;
}

//尾插法建立双链表,在双链表的尾部插入新结点,因此,应该声明一个尾指针r并始终指向尾结点。
DLinkList TailInsert(DLinkList &L){
    InitList(L);
    DNode *s,*r=L;
    int x;
    cin>>x;
    while(x!=9999){
        s = (DNode *)malloc(sizeof(DNode));
        s->data = x;
        s->next = NULL;
        s->pre = r;
        r->next = s;
        r = s;
        cin>>x;
    }
    return L;
}

//求双链表的长度
int Length(DLinkList L){
    DNode *p = L->next;
    int len = 0;
    while(p){
        len++;
        p = p->next;
    }
    return len;
}

//按值查找:查找x在L中的位置,此处与单链表相同,用不到pre
DNode *LocateElem(DLinkList L, int x){
    DNode *p = L->next;
    while(p && p->data != x){
        p = p->next;
    }
    return p;
}

//按位查找:查找在双链表L中第i个位置的结点,此处与单链表相同,用不到pre
DNode *GetElem(DLinkList L, int i){
    int j=1;
    DNode *p = L->next;
    if(i==0) return L;
    if(i<1) return NULL;
    while(p && j<i){
        p = p->next;
        j++;
    }
    return p; //如果i大于表长,p=NULL
}

//删除,将双链表中的第i个结点删除
void Delete(DLinkList &L, int i){
    if(i<1 || i>Length(L)){
        cout<<"delete failed"<<endl;
        return;
    }
    DNode *p = GetElem(L,i-1);
    DNode *q = p->next;
    p->next = q->next; //1
    q->next->prior = p; //2
    free(q);
}

//判断是否为空
bool Empty(DLinkList L){
    if(L->next == NULL){
        cout<<"L is null"<<endl;
        return true;
    }else{
        cout<<"L is not null"<<endl;
        return false;
    }
}

//遍历
void PrintList(DLinkList L){
    DNode *p = L->next;
    while(p){
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}
3.循环链表

 与将单链表相比,单向循环终点结点的指针域由 空指针 改为 指向头结点,使整个链表形成一个环。若不是尾结点,则cur->next != head。其他操作基本与单链表一致。

与双链表相比,双向循环链表尾结点的next指向head,head的pre指向最后一个结点,构成一个环

4.静态链表

借助数组来描述线性表的链式存储结构,结点也有数据域data和指针域next,与前面说的链表中的指针不同的是,这里的指针是结点的相对地址(数组下标),又称游标。和顺序表一样,静态链表要预先分配一块连续的内存空间。

具体实现可以看看这里(

静态链表详解(C语言版)_c语言实现静态链表-CSDN博客

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值