C语言复习笔记(六)之顺序表和链表

一、顺序表

1、顺序表概念

        顺序存储的线性表

2、顺序表的初始化

(1)头文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

(2)管理顺序表的结构体

typedef struct 
{
    int capacity;//顺序表容量
    int last;//最末元素下标
    int *data;//顺序表,以整型数据为例
}sequenceList;

(3)顺序表的初始化

sequenceList * init_list(int cap)
{
    sequenceList *list=malloc(sizeof(sequenceList));//给结构体本身分配空间
    if(list != NULL)//如果成功
    {
        list->data=malloc(sizeof(int)*cap);//给顺序表分配空间
        if(list -> data == NULL)//给顺序表分配空间失败,capacity和last就分配不了了,不用赋值了
        {
            free(list);//管理结构体没有意义,将管理结构体释放
            return NULL;
        }
        //如果给顺序表分配空间成功就给剩下的两个结构体成员变量赋值
        list -> capacity=cap;
        list-> last=-1;
    }
    return list;
}

(4)main函数

int main()
{
    sequenceList *list=init_list(10);//容量10
    if(list==NULL)//判断初始化到底有没有成功,如果失败
    {
        printf("初始化顺序表失败\n");
        exit(0);//退出程序
    }
    else 
        printf("初始化顺序表成功\n");
    return 0;
}

3、顺序表的增删节点

3.1 顺序表的增添节点

bool isFULL(sequenceList *list)
{
    return list->last==list->capacity-1;
}
//在顺序表表头插入一个新数据
bool insert(sequenceList *s,int data)
{
    if(isFULL(s))
        return false;
    //将原有数据全部往后挪一位
    for(int i=s->last;i>=0;i--)
        s->data[i+1]=s->data[i];
    //将新数据置入表头
    s->data[0]=data;
    s->last++;
    return true;
}

3.2 顺序表的删除节点

//判断顺序表是否为空
bool isEmpty(sequenceList *list)
{
    return list -> last==-1;
}
//查看当前顺序表的元素
void show(sequenceList *list)
{
    if(isEmpty(list))
        return;
    for(int i=0;i<=list->last;i++)
        printf("%d\t",list->data[i]);
    printf("\n");
}
//将顺序表中指定的某个元素数据删除掉
bool removeNode(sequenceList *list,int data)
{
    if(isEmpty(list))
        return false;
    //找到要删除的节点的位置
    int i,pos=-1;
    for(i=0;i<=list->last;i++)
    {
        if(list->data[i]==data)
        {
            pos=i;
            break;
        }
    }
    //找不到要删除的节点的位置
    if(i>list->last)
        return false;
    return list;
    //将所有数据全部往前挪一位
        list->data[i]=list->data[i+1];
    list->last--;
    return true;
}

4 、顺序表的销毁 

void destroy(sequenceList *list)
{
    if(list==NULL)
        return;
    free(list->data);
    free(list);
}

 3.4 main函数

int main()
{
    sequenceList *list=init_list(10);//容量10
    if(list==NULL)//判断初始化到底有没有成功,如果失败
    {
        perror("初始化顺序表失败\n");
        exit(0);//退出程序
    }
    else 
        printf("初始化顺序表成功\n");

    int n;
    while(1)
    {
        scanf("%d",&n);
        if(n>0)
        {
            if(!insert(list,n))
            {
                printf("容量已满,插入失败\n");
                continue;
            }
        }
        else if(n<0)
        {
            if(!removeNode(list,-n))
            {
                printf("查无此数,删除失败!\n");
            }
        }
        show(list);
    }
    destroy(list);
    return 0;
}

二、链表

1、链表的概念

        链式存储的线性表,简称链表。

2、链表的初始化

2.1 管理链表的结构体

typedef struct node
{
    int data;
    struct node *next;//指向下一个节点的指针
}node;

2.2 链表的初始化

2.2.21 单链表的初始化
node *initList()
{
    node *head=malloc(sizeof(node));
    if(head != NULL)
    {
        head->next=NULL;
    }
    return head;
}
2.2.2 单向循环链表的初始化
node *initList()
{
    node *head=malloc(sizeof(node));
    if(head != NULL)
    {
        head->next=head;
    }
    return head;
}
2.2.3 双向循环链表的初始化
typedef struct ListNode
{
    int data;              // 用于存储链表的值
    struct ListNode *prev; // 指向当前链表节点前一个节点
    struct ListNode *next; // 指向当前链表节点后一个节点
} ListNode;

ListNode *head = NULL;
ListNode *tail = NULL;

ListNode *init_list_node(int val)
{
    ListNode *node = malloc(sizeof(ListNode));

    if (node == NULL)
    { // malloc 申请内存空间失败
        return NULL;
    }

    node->data = val;
    node->prev = NULL;
    node->next = NULL;
    // 定义了在链表中的地位
    head = node;
    tail = node;

    return node;
}

3、链表的增删节点

3.1 头插法

3.1.1 单链表
int addHeadBefore(int val)
{
    // 创建一个新的节点
    node *n = malloc(sizeof(node));
    if (n == NULL)
    {
        return 0;
    }

    n->data = val;

    // 让当前链表节点直线旧链表的头结点
    n->next = head;

    // 把head名头让给新的节点
    head = n;
}
3.1.2 循环链表
//头插法
void insertHead(node *head,node *new)
{
    new->prev=head;
    new->next=head->next;
    head ->next=new;
    head->next->prev=new;
}
3.1.3 双向循环链表
ListNode *insertbefore(ListNode *n, int val)
{
    // 创建新节点
    ListNode *newNode = malloc(sizeof(ListNode));
    newNode->data = val;
    newNode->next = NULL;
    newNode->prev = NULL;

    ListNode *oldPrevNode = n->prev;

    n->prev = newNode;
    newNode->next = n;

    if (oldPrevNode != NULL)
    {
        newNode->prev = oldPrevNode;
        oldPrevNode->next = newNode;
    }
    else
    {
        head = newNode;
    }

    return newNode;
}

3.2 尾插法

3.2.1 单链表
int addTailAfter(int val)
{
    // 创建一个新的节点
    node *n = malloc(sizeof(node));
    if (n == NULL)
    {
        return 0;
    }

    n->data = val;
    n->next = NULL;

    // 让当前链表最后一个节点指向 新节点
    tail->next = n;
    // 把tail名头让给新的节点
    tail = n;
}
3.2.2 循环链表
//尾插法
void insertTail(node *head,node *new)
{
    new->prev=head->prev;
    new->next=head;
    head->prev->next=new;
    head->prev=new;
}
3.2.3 双向循环链表

4、链表的销毁

41 单链表

node *destory(node *head)
{
    for(node *tmp=head,*n=tmp->next;tmp != NULL;tmp=n)
    {
        n=tmp->next;
        free(tmp);
    }
    return NULL;
}

4.2 循环链表

node *destroy(node *head)
{
    node *p;
    for(p=head->next;p!=head;p=head->next)
    {
        removeNode(p);
        free(p);
    }
    //释放头节点
    free(head);
    return NULL;
}

4.3 双向循环链表

// 销毁链表, 从头部开始销毁
int destoryByHead()
{
    ListNode *n = head;

    while (n != NULL)
    {
        // 先拿到下一个
        head = n->next;
        printf("%d \n", n->data);
        free(n);
        printf("free %d  \n", n->data);
        n = head;
    }

    head = NULL;

    return 1;
}
// 销毁链表, 从尾部开始销毁
int destoryByTail()
{
    ListNode *n = tail;

    while (n != NULL)
    {
        // 先拿到上一个
        tail = n->prev;
        printf("%d \n", n->data);
        free(n);
        printf("free %d  \n", n->data);
        n = tail;
    }
    tail = NULL;

    return 1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值