数据结构之链表(Linked-List)及操作

一、 数据结构之链表(Linked-List)

线性表是最常用的存储结构,线性表的每个单元称为元素,元素拥有一个数据及一个地址线性表有两种物理存储方式:顺序存储方式和链式存储方式数组是具有代表性的顺序存储方式的线性表,单链表是具有代表性的链式存储方式的线性表。


1.数组

数组的内存是连续分配的,可以通过数组的索引直接获取对应的数据,其索引就是线性表中所说的元素的“地址”,但索引不是地址。

2.单链表

单链表的内存的是链式的,也就是不连续的,元素中的地址指向链表中下一个元素的地址。

关于单链表的头指针和头结点

头指针不是头结点。头指针指向头结点,而头结点通常data域为NULL或者为单链表的length,在如下数据结构中,

typedef struct LinkedListNode
{//定义单链表
    int value;
    struct LinkedListNode *next;
}*LinkedList;

假如定义
LinkedList L,则L是我们需要的头指针(头指针在单链表是必须的而头结点不是),
又再L=(LinkedList malloc (sizeof(LinkedListNode)); 这就申请了一个结点,这里第一个结点也就是头结点。

定义单链表

单链表有两个域,data域用于存放数据,next域用于存放下一个结点的地址。

typedef struct LinkedListNode
{//定义单链表
    int value;
    struct LinkedListNode *next;
}*LinkedList;

创建单链表

LinkedList CreateLinkedList()
{
    LinkedListNode* newNode = (LinkedListNode*)malloc(sizeof(LinkedListNode));
    if (newNode != NULL)
    {
        newNode->value = 0;
        newNode->next = NULL;
        return newNode;
    }
    else
    {
        return NULL;
    }
}

创建新结点

LinkedListNode* CreateLinkedListNode(int val)
{//创造新的单链表结点
    LinkedListNode* newNode = (LinkedListNode*)malloc(sizeof(LinkedListNode));
    if (newNode != NULL)
    {
        newNode -> value = val;
        newNode->next = NULL;
        return newNode;
    }
    else
    {
        return NULL;
    }
}

前插法插入新元素(新结点)

前插:在头结点后面插入新元素,则头结点后面的元素永远是新元素,设链表头结点head,元素x1,x2,x3按序插入,设链表头尾走向从左到右
(1)Insert后:head x1
(2)Insert后:head x2 x1
(3)Insert后:head x3 x2 x1

void anteriorInsert(LinkedListNode* head, int val)
{
    LinkedListNode* newNode = CreateLinkedListNode(val);
    newNode->next = head->next;//先使新元素的指针域next指向头结点的next
    head->next = newNode;//再使头结点的next指向新元素
    head->value++; //可以用头结点的data域存储链表的length
}

后插法插入新元素(新结点)

后插:在尾指针所指向的结点后面插入新元素,尾指针指向的结点永远是新元素,设元素x1,x2,x3按序插入,设链表头尾走向从左到右。多设置一个尾指针使操作更方便,否则需要遍历链表。
(1)Insert后:x1
(2)Insert后:x1 x2
(3)Insert后:x1 x2 x3

void posteriorInsert(LinkedListNode* head, LinkedListNode* tail, int val)
{
    LinkedListNode* newNode = CreateLinkedListNode(val);
    tail->next = newNode;//先使尾指针的next指向新元素
    tail = tail->next;//再使尾指针指向新元素
    head->value++; //可以用头结点的data域存储链表的length
}

按data域的值查找结点

这里找是链表中找到第一个data域等于val的结点,不是所有结点

LinkedListNode* SearchByVal(LinkedList L, int val)
{
    LinkedListNode* Node = L->next;
    while (Node)
    {
        if (Node->value == val)
        {
            //找到马上return
            return Node;
        }
        Node = Node->next;
    }
    return Node;
}

按data域的值修改结点的data域的值

void UpdateVal(LinkedList L, int preVal , int aftVal)
{//将所有data域等于preVal的结点的data域值修改为aftVal
    LinkedListNode* Node = L->next;
    while (Node)
    {
        if (Node->value == preVal)
        {
            Node->value = aftVal;
        }
        Node = Node->next;
    }
}

按data域的值删除结点

这里是找到第一个data域等于val的结点将其删除

void DeleteByVal(LinkedListNode* head, int val)
{
    if (head->next == NULL)
    {
        cout << "LinkedList is null" << endl;
    }
    else
    {
        //从头结点开始遍历
        LinkedListNode* previousNode = head, *currentNode = head->next;
        while (currentNode)
        {
            if (currentNode->value == val)
            {
                //删除目标结点
                previousNode->next = currentNode->next;
                free(currentNode);
                head->value--;
                break;
            }   
            else
            {
                currentNode = currentNode->next;
                previousNode = previousNode->next;
            }
        }
    }
    return;
}

清空链表

void FreeLinkedList(LinkedList L)
{
    for (LinkedListNode* temp = L; L!= NULL; temp = L)
    {
        L = L->next;
        free(temp);
    }
}

关于单链表后插法的疑问

既然后插代码如上,那么应该如何遍历,从尾指针往前遍历吗,那感觉头指针有点楞。从头结点往后遍历,但是如上代码的头结点的next为NULL,于是尴尬。求大神解答。

猜你喜欢

转载自blog.csdn.net/qq_31729917/article/details/80955028
今日推荐