链表的定义和C语言的实现

首先来谈谈链式存储结构:
(1)特点:用一组任意的存储单元存储线性表中的数据元素;这组存储单元可以是连续的,也可以是不连续的;每个数据元素除了存储数据外,还要存储前驱、后继元素的地址。
1、单链表:n个节点按链式存储结构存储,每一个结点只包含一个指针域。下面来分享一下链表基本功能和C语言中的实现。
(1)线性表的单链表存储结构:

typedef int DataType;
typedef struct Node
{
    DataType data;//数据域
    struct Node *next;//指针域
}Node;

(2)获取指定位置的元素:

Node* getptr(Node *head, int pos)
{
    Node *p = head;//p与head指向同一个位置
    if(p == NULL || pos == 0)//p为空的时候,代表链表为空
    {
        //当pos为0时就是head的指向,所以返回head
        return head;//返回一个空指针
    }
    for(int i = 0; p && i < pos; i++ )//必须要加上p&&这句话防止p为空指针
    {
        p = p->next;
    }
    return p;
}

(3)获取单链表中结点个数:

int getSize(Node *head)
{
    int size = 0;
    Node *p = head;
    while(p)//判断P是否为空
    {
        size++;
        p = p->next;
    }
    return size;
}

(4)单链表中插入

/*********************************************************
* head:为二级指针
* position:插入的位置
* d:数据
*********************************************************/
bool insert(Node **head, int position, DataType d)
{
    //判断是否可以插入
    if(position < 0 || position > getSize(*head))//先判断是否正确
    {
        return false;
    }
    //分配一个要插入数据的空间
    Node *node = (Nodee *)malloc(sizeof(Node));
    node->data = d;
    node->next = NULL;//令当前指针指向为空
    if(position == 0)
    {
        //表示在头部或者在空链表中插入
        node->next = *head;
        *head = node;
        return true;
    }
    //表示在任何位置插入数据
    Node *p = getptr(*head, position - 1);//获取前面一个数据的地址
    //进行插入操作
    Node *r = p->next;
    node->next = r;
    p->next = node;
    return true;
}

(5)单链表的删除:

/******************************************************
* pos 为删除的位置
******************************************************/
bool erase(Node **head, int pos)
{
    //判断删除的位置是否正确
    if(pos < 0 || pos >= getSize(*head))
    {
        return false;
    }
    //删除头结点
    if(pos == 0)
    {
        *head = (*head)->next;//将指向他的指针释放
        free(p);
        p = NULL;//这一句话可以不要,但是这个是一个好习惯
        return true;
    }
    //删除中间和最后的结点
    p = getptr(*head, pos - 1);
    Node *q = p->next;
    p->next = q->next;
    free(q);
    q = NULL;//好习惯,如果没有写可能在调试时会崩溃
    
    return true;
}

(6)两个线性表的合并

/****************************************************
* 通过找到第一个链表的尾指针,将尾指针指向第二个链表的头指针来实现
* 两个链表的合并
****************************************************/
void union(Node *a, Node *b)
{
    Node *p = a;
    while(p->next)
    {
        p = p->next;
    }
    p->next = b;
}

(7)将线性表倒置:

/**********************************************************
* head:为链表的头指针                                                                                  
**********************************************************/
void reverse(Node **head)
{
    Node *p = *head;
    Node *q = p->next;
    if(q == NULL)
    {
        return;
    }
    Node *r = q->next;
    if(p == *head)
    {
        p->next = NULL;
    }
    while(true)
    {
        q->next = p;
        if(r == NULL)
        {
            *head = q;
            break;
        }
        else
        {
            p = q;
            q = r;
            r = r->next;
        }
    }
} 

(8)线性表的遍历:

void print(DataType d)
{
    printf("%d\n", d);
}
// 使用函数指针的好处:当函数不是执行打印操作时可以随时改变函数的功能。
void trave(Node *head, void (*fun)(DataType))
{
    Node *p = head;
    while(p)
    {
        fun(p->data);
        p = p->next;
    }
}

主函数的调用:

void main(void)
{
    Node *head = NULL;
    //... 
    Node *p = getptr(head, 3);//获取3中的元素
    
    int Len = getSize(head);//获取结点个数
    
    insert(&head, 0, 10);//在头插入
   insert(&head, 3, 5);//在任意位置插入
   
   //删除代码示例
   erase(&head, 0);//删除头结点
   erase(&head, 1);//删除中间的结点
   
   trave(head, print);
}
发布了45 篇原创文章 · 获赞 15 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/CHQC388/article/details/88920793