单链表的基本操作

单链表
  单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
这里写图片描述
链表又分为带头结点的链表以及不带头结点的链表;
下面我们讨论不带头结点的链表的基本操作;
我们要完成的基本操作是:
初始化
打印
尾部插入
尾部删除
头部插入
头部删除
查找指定元素返回地址
指定位置前插入
删除指定位置元素
删除指定元素
删除所有的指定元素
链表长度
冒泡排序
选择排序
选择排序的优化
销毁链表

首先定义一个结构体,由于单链表是用任意的存储单元存储元素,所以需要把这些任意的存储单元连接起来就需要设置一个指针,使结点之间相互联系起来。

#define DataType int
typedef struct Node{
    DataType data;
   struct Node* next;
}linklist;

初始化
为单链表设置一个头指针

void LinkListInit(linklist **phead)
{
    assert(phead);
    //指针初始化
    *phead = NULL;
}

打印
循环打印

void LinkListPrint(linklist *head)
{
    linklist *cur = head;
    while (cur != NULL)
    {
        printf("%d  ",cur->data);
        cur = cur->next;
    }
    printf("\n");
}

尾插法
  尾插法分为两种情况:一种是链表为空的情况下插入,另一种是链表不为空的情况下插入,链表为空时需要修改头指针,使头指针指向对应的结点,链表不为空时,从头遍历找到最后一个结点,使这个结点的next指针域,指向要插入的结点。

void LinkListPushBack(linklist **phead, DataType d)
{
    linklist *node = NULL;
    linklist *cur = NULL;
    assert(phead);
    node = BuyNode(d);
    //1.链表中无结点
    if (*phead == NULL)
    {
       *phead = node;
    }
    //2.链表中已经有结点
    else
    {
        cur = *phead;
        //找最后一个结点连接
        while (cur->next!=NULL)
        {
            cur = cur->next;
        }
        cur->next = node;
    }
}

  其中BuyNode函数为结点开辟空间,若开辟成功返回空间的地址

linklist *BuyNode(DataType d)
{
    linklist *node = NULL;
    node = (linklist*)malloc(sizeof(linklist));
    if (node == NULL)
    {
        printf("空间开辟失败!\n");
        return NULL;
    }
    else
    {
        node->data = d;
        node->next = NULL;
        return node;
    }
}

尾删法
  尾删法分为三种情况一种是该链表为空链表,一种是该链表只有一个结点,一种是该链表有多个结点,链表为空时不能删除,链表只有一个结点时,将该空间释放后,使头指针为空,链表有多个结点时,遍历找到最后一个并释放空间,使得倒数第二个的next指针域置为空。

void LinkListPopBack(linklist **phead)
{
    linklist *cur = NULL;
    linklist *pre = NULL;
    assert(phead);
    //1.无结点
    if (*phead == NULL)
    {
        printf("链表为空,无法删除!\n");
        return;
    }
    //2.只有一个头结点
    else if ((*phead)->next == NULL)
    {
        free(*phead);
        *phead = NULL;
    }
    //3.多个结点
    else
    {
        cur = *phead;
        while (cur->next != NULL)
        {
            pre = cur;
            cur = cur->next;
        }
        free(cur);
        cur = NULL;
        pre->next = NULL;
    }
}

头插法
  头插法分为两种情况,一种是链表为空时插入,另一种是链表不为空时插入,当链表为空时,使头指针直接指向对应的结点,链表不为空时,使结点的next指针域指向原链表的头结点,然后修改头指针指向新插入的结点。

void LinkListPushFront(linklist **phead, DataType d)
{
    linklist *node;
    node = BuyNode(d);
    assert(phead);
    //1.无结点
    if (*phead == NULL)
    {
        *phead = node;
    }
    //2.有结点
    else
    {
        node->next =*phead;
        *phead = node;
    }
}

头删法
   头删法分为三种情况一种是链表为空,一种是链表只有一个结点,一种是有多个结点,链表为空时不能删除,链表只有一个结点时,将头指针置为空,有多个结点时,头指针后移,释放第一个结点。

void LinkListPopFront(linklist ** phead)
{

    linklist *cur = NULL;
    assert(phead);
    //1.无结点
    if (*phead == NULL)
    {
        printf("链表为空,无法删除!\n");
        return;
    }
    //2.只有一个结点
    else if ((*phead)->next == NULL)
    {
        free(*phead);
        *phead = NULL;
    }
    //3.多个结点
    else
    {
        cur = *phead;
        *phead = (*phead)->next;
        free(cur);
        cur = NULL;
    }
}

查找指定元素返回结点
  

linklist * LinkListFind(linklist *head, DataType d)
{
    linklist *cur = NULL;
    cur = head;
    while (cur != NULL)
    {
        if (cur->data == d)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

指定位置前插入
   指定位置前插入分为两种情况,一种是在第一个结点前插入,另一种是在其余结点前插入。在第一个节点前插入采用头插法。在其余结点前插入采用两个指针。

void Insert(linklist **phead, int pos, DataType d)
{
    linklist *node = NULL;
    linklist *cur = NULL;
    assert(phead);
    node = BuyNode(d);
    //1.第一个结点前插入
    if (pos == 1)
    {
        //头插法
        node->next = *phead;
        *phead = node;
    }
    //2.其余结点前插入
    else
    {
        cur = *phead;
        pos = pos - 2;
        while (pos--)
        {
            cur = cur->next;
        }
        node->next = cur->next;
        cur->next = node;
    }
}

删除指定位置元素
   删除指定位置元素分为两种情况,一种是删除头结点,另一种是删除其他结点。删除头结点采用头删法。

void Erase(linklist **phead, int pos)
{
    linklist* cur = NULL;
    linklist* pre = NULL;
    assert(phead);
    //1.删除第一个元素
    if (pos == 1)
    {
        //头删法
        cur = *phead;
        *phead = (*phead)->next;
        free(cur);
    }
    //2.删除其他元素
    else
    {
        cur = *phead;
        pos = pos - 1;
        while (pos--)
        {
            pre = cur;
            cur = cur->next;
        }
        pre->next = cur->next;
        free(cur);
        cur = NULL;
    }
}

删除指定元素
   删除指定元素分为两种情况,一种是该元素是头结点,一种是该链表不是头结点,元素为头结点时采用头删法

void Remove(linklist **phead, DataType d)
{
    linklist *cur = NULL;
    linklist *pre = NULL;
    pre = *phead;
    cur = *phead;
    assert(phead);
    //找到该元素的位置
    while (cur != NULL)
    {
        if (cur->data == d)
        {
            break;
        }
        cur = cur->next;
    }
    if (cur != NULL)
    {
        if (cur == *phead)
        {
            //头删法
            *phead = (*phead)->next;
            free(cur);
            cur = NULL;
        }
        else
        {
            while (pre->next != cur)
            {
                pre = pre->next;
            }
            pre->next = cur->next;
            free(cur);
            cur = NULL;
        }
    }
}

删除所有的指定元素
   遍历一次链表,把与指定元素相同的结点全部删掉。

void RemoveAll(linklist **phead, DataType d)
{
    linklist *cur = NULL;
    linklist *pre = NULL;
    linklist *node = NULL;
    assert(phead);
    node = *phead;
    pre = *phead;
    cur = *phead;
    while (cur != NULL)
    {
        node = cur;
        if (node->data == d)
        {
            if (node == *phead)
            {
                //头删法
                *phead = (*phead)->next;
                free(node);
                node = NULL;
                cur = cur->next;
            }
            else
            {
                while (pre->next != node)
                {
                    pre = pre->next;
                }

                pre->next = node->next;
                free(node);
                node = NULL;
                cur = cur->next;
            }
        }
        else
        {
            cur = cur->next;
        }
    }
}

链表长度
  

int Getlength(linklist *head)
{
    linklist *cur = NULL;
    cur = head;
    int count = 0;
    while (cur != NULL)
    {
        count++;
        cur = cur->next;
    }
    return count;
}

冒泡排序
   外循环为链表的长度-1次,设置一个尾结点,外循环每执行一次,尾结点向前移动一步。

void LinkListBubblesort(linklist *head)
{
    linklist *cur = head;
    linklist *tail = head;
    DataType node = 0;
    int length = 0;
    int flag = 0;
    //尾结点,tail指向空
    while (tail != NULL)
    {
        tail = tail->next;
    }
    length = Getlength(head) - 1;
    //外循环,循环链表长度-1次
    while (length--)
    {
        flag = 0;
        cur = head;
        while (cur->next != tail)
        {
            if (cur->data > cur->next->data)
            {
                //交换
                node = cur->data;
                cur->data = cur->next->data;
                cur->next->data = node;
                flag = 1;
            }
            cur = cur->next;
        }
        tail = cur;
        //若为1,则证明链表已经有序
        if (flag == 0)
        {
            return;
        }
    }
}

选择排序
  

void LinkListSelectsort(linklist *head)
{
    linklist *max = head;  //最大值指针
    linklist *tail = head;
    linklist *cur = NULL;
    DataType node = 0;
    int length = Getlength(head) -1 ;
    //尾结点,tail指向空
    while (tail != NULL)
    {
        tail = tail->next;
    }
    while (length--)
    {
        max = head;
        cur = head->next;  
        while (cur->next != tail)
        {
            //找到链表的最大值
            if (cur->data > max->data)
            {
                max = cur;
            }
            cur = cur->next;
        }
        //比较链表尾结点是不是最大值
        if (cur->data > max->data)
        {
            max = cur;
        }
        if (max != cur)
        {
            //交换
            node = max->data;
            max->data = cur->data;
            cur->data = node;
        }
        tail = cur;
    }
}

选择排序的优化
  

void LinkListSelectsortOP(linklist *head)
{
    linklist *max = head;  //最大值指针
    linklist *min = head;  //最小值指针
    linklist *tail = head;
    linklist *pre = head;
    linklist *cur = NULL;
    DataType node = 0;
    int length = Getlength(head) /2;
    //尾结点,tail指向空
    while (tail != NULL)
    {
        tail = tail->next;
    }
    while (length--)
    {
        max = pre;
        min = pre;
        cur = pre->next;
        while (cur->next != tail)
        {
            //找到链表的最大值
            if (cur->data > max->data)
            {
                max = cur;
            }
            //找到链表的最小值
            if (cur->data < min->data)
            {
                min = cur;
            }
            cur = cur->next;
        }
        //比较链表尾结点是不是最大值
        if (cur->data > max->data)
        {
            max = cur;
        }
        //比较链表尾结点是不是最小值
        if (cur->data < min->data)
        {
            min = cur;
        }
        if (max != cur)
        {
            //交换
            node = max->data;
            max->data = cur->data;
            cur->data = node;
        }
        if (min == cur)
        {
            min = max;
        }
        if (min != pre)
        {
            //交换
            node = min->data;
            min->data = pre->data;
            pre->data = node;
        }
        pre = pre->next;
        tail = cur;
    }
}

销毁单链表
   从头开始删除,删除完后将头结点置空。

void DestroyLinklist(linklist ** phead)
{
    linklist *cur = NULL;
    linklist *pre = NULL;
    assert(phead);
    cur = *phead;
    while (cur != NULL)
    {
        pre = cur;
        cur = cur->next;
        free(pre);
        pre = NULL;
    }
    *phead = NULL;
}

.h头文件

#include<stdlib.h>
#include<assert.h>
#include<stdio.h>


#define DataType int
typedef struct Node{
    DataType data;
   struct Node* next;
}linklist;

//链表初始化
void LinkListInit(linklist **phead);
//尾插法
void LinkListPushBack(linklist **phead, DataType d);
//打印
void LinkListPrint(linklist *head);
//尾删法
void LinkListPopBack(linklist **phead);
//头插法
void LinkListPushFront(linklist **phead, DataType d);
//头删法
void LinkListPopFront(linklist ** phead);
//查找函数,返回结点地址
linklist * LinkListFind(linklist * head, DataType d);
//在指定位置之前插入一个元素
void Insert(linklist **phead, int pos, DataType d);
//删除指定位置元素
void Erase(linklist **phead, int pos);
//删除指定元素
void Remove(linklist **phead, DataType d);
//删除所有的指定元素
void RemoveAll(linklist **phead, DataType d);
//链表长度
int Getlength(linklist *head);
//冒泡排序
void LinkListBubblesort(linklist *head);
//选择排序
void LinkListSelectsort(linklist *head);
//选择排序的优化
void LinkListSelectsortOP(linklist *head);
//销毁链表
void DestroyLinklist(linklist **phead);

.c测试文件

#include"LinkList.h"
linklist *head;
//测试尾部插入和尾部删除
void TestTail()
{
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 3);
    LinkListPushBack(&head, 4);
    //打印
    LinkListPrint(head);
    //尾删法
    LinkListPopBack(&head);
    //打印
    LinkListPrint(head);
}

//测试头部插入和头部删除
void TestHead()
{
    //链表初始化
    LinkListInit(&head);
    //头插法
    LinkListPushFront(&head, 4);
    LinkListPushFront(&head, 3);
    LinkListPushFront(&head, 2);
    LinkListPushFront(&head, 1);
    //打印
    LinkListPrint(head);
    //尾删法
    LinkListPopFront(&head);
    LinkListPopFront(&head);
    LinkListPopFront(&head);
    LinkListPopFront(&head);
    LinkListPopFront(&head);

    //打印
    LinkListPrint(head);
}

//测试查找函数以及指定位置增加和删除
void TestFind()
{
    linklist * node = NULL;
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 3);
    LinkListPushBack(&head, 4);
    //打印
    LinkListPrint(head);
    //查找函数,返回结点地址
    node=LinkListFind(head, 4);
    if (node != NULL)
    {
        //打印
        LinkListPrint(node);
        //在指定位置之前插入一个元素
        Insert(&head, 4, 5);
        //打印
        LinkListPrint(head);
        //删除指定位置元素
        Erase(&head,4);
        //打印
        LinkListPrint(head);
    }
    else
    {
        printf("找不到该元素!\n");
    }
}

//测试删除指定元素和删除所有的指定元素
void TestErase()
{
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 3);
    LinkListPushBack(&head, 4);
    LinkListPushBack(&head, 1);
    //打印
    LinkListPrint(head);
    //删除指定元素
    Remove(&head, 1);
    //打印
    LinkListPrint(head);
    //删除所有的指定元素
    RemoveAll(&head, 1);
    //打印
    LinkListPrint(head);
}

//测试链表的长度
void TestLength()
{
    int length = 0;
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 3);
    LinkListPushBack(&head, 4);
    LinkListPushBack(&head, 1);
    //打印
    LinkListPrint(head);
    //链表长度
    length=Getlength(head);
    printf("Length=%d\n", length);
}

//测试链表的冒泡排序
void TestBubble()
{
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 8);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 8);
    LinkListPushBack(&head, 4);
    LinkListPushBack(&head, 6);
    //打印
    LinkListPrint(head);
    //冒泡排序
    LinkListBubblesort(head);
    //打印
    LinkListPrint(head);
}

//测试链表的选择排序
void TestSelectSort()
{
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 8);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 8);
    LinkListPushBack(&head, 4);
    LinkListPushBack(&head, 10);
    //打印
    LinkListPrint(head);
    //选择排序
    LinkListSelectsort(head);
    //打印
    LinkListPrint(head);
}

//测试链表的选择排序的优化
void TestSelectSortOP()
{
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 8);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 8);
    LinkListPushBack(&head, 4);
    LinkListPushBack(&head, 10);
    //打印
    LinkListPrint(head);
    //选择排序的优化
    LinkListSelectsortOP(head);
    //打印
    LinkListPrint(head);
}

//测试销毁链表
void TestDestory()
{
    //链表初始化
    LinkListInit(&head);
    //尾插法
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 2);
    LinkListPushBack(&head, 1);
    LinkListPushBack(&head, 3);
    LinkListPushBack(&head, 4);
    LinkListPushBack(&head, 1);
    //打印
    LinkListPrint(head);
    //销毁链表
    DestroyLinklist(&head);
    //打印
    LinkListPrint(head);
}
void test()
{
    //测试尾部插入和尾部删除
    //TestTail();
    //测试头部插入和头部删除
    //TestHead();
    //测试查找函数以及指定位置增加和删除                   
    //TestFind();
    //测试删除指定元素和删除所有的指定元素
    //TestErase();
    //测试链表的长度
    //TestLength();
    //测试链表的冒泡排序
    //TestBubble();
    //测试链表的选择排序
    //TestSelectSort();
    //测试链表的选择排序的优化
    //TestSelectSortOP();
    //测试销毁链表
    //TestDestory();    
}
int main()
{
    test();
    system("pause");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值