单链表
单链表存储一个直接后继的地址,用一组任意的存储单元存储线性表中的元素。
数据域(数据元素)+指针域(指示后继元素存储位置) = 结点,如下图:a和b是两个结点,其中a的指针域保存了指向b的地址。
以线性表中第一个数据元素a1的存储地址作为线性表的地址,称作线性表的头指针。
单链表查找指定位置上的数据:
从头结点开始,顺着链表各个结点的next指针一直找到对应的位置,返回对应的数据。
单链表的插入操作:
插入元素首先找到要插入位置的前一个结点a,然后建立新结点,将新结点的指针域指向a结点的next结点,在将a结点的next结点指向新结点。
单链表删除指定位置上的数据:
先找到要删除结点的前一个元素a,然后将a的next指针指向要删除结点的next位置,最后时放掉结点。
其它操作不详述,下面是代码:
这里用了头结点,指向第一个结点,头结点中的数据用来存放整个链表结点的个数,可能与网上其它的代码不是很一样,但是思想是一致的。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//定义链表的节点
struct Node
{
int data;
struct Node *next;
};
typedef struct Node Node;
//链表的头,指点第一个结点(如果有的话),存储的内容是链表元素的个数
typedef struct Node *LinkList;
//初始化单链表
void InitialList(LinkList *L);
//单链表添加元素
void PushElement(LinkList *L, int pos, int elem);
//创建结点
Node *CreateNode(int elem);
//在首部插入结点
void PushFront(LinkList *L, int elem);
//删除首部的元素
void PopFront(LinkList *L);
//在尾部插入结点
void PushBack(LinkList *L, int Elem);
//删除尾部的元素
void PopBack(LinkList *L);
//查找某个位置的元素
int FindElemAtPos(LinkList *L, int pos);
//删除指定位置的元素
void PopElement(LinkList *L, int pos);
//输出所有元素
void viewlist(LinkList *L);
int main()
{
LinkList L;
InitialList(&L);
PushFront(&L, 100);
PushFront(&L, 200);
PushElement(&L, 1, 300);
PushBack(&L, 500);
for (int i = 0; i < 10; i++)
{
PushFront(&L, i);
}
viewlist(&L);
printf("
The element at pos 11 is %d
", FindElemAtPos(&L, 11));
printf("
Pop the element at pos 6:
");
PopElement(&L, 6);
viewlist(&L);
printf("
Pop the front element:
");
PopFront(&L);
viewlist(&L);
printf("
Delete the element at back:
");
PopBack(&L);
viewlist(&L);
printf("
The number of elements is %d
", (*L).data);
system("pause");
return 0;
}
void InitialList(LinkList *L)
{
(*L) = (Node *)malloc(sizeof(Node));
(*L)->data = 0;
(*L)->next = NULL;
}
void PushElement(LinkList *L, int pos, int elem)
{
int temppos = 0;
Node *p = (*L);
while (temppos != (pos - 1))
{
p = p->next;
temppos++;
}
Node *newNode = CreateNode(elem);
newNode->next = p->next;
p->next = newNode;
(*L)->data++;
}
Node *CreateNode(int elem)
{
Node *p = (Node *)malloc(sizeof(Node));
p->data = elem;
p->next = NULL;
return p;
}
void PushFront(LinkList *L, int elem)
{
Node *newNode = CreateNode(elem);
newNode->next = (*L)->next;
(*L)->next = newNode;
(*L)->data++;
}
void PopFront(LinkList *L)
{
Node *P = (*L)->next;
(*L)->next = P->next;
free(P);
(*L)->data--;
}
void PushBack(LinkList *L, int Elem)
{
Node *newNode = CreateNode(Elem);
Node *tempNode = (*L);
while (tempNode->next != NULL)
{
tempNode = tempNode->next;
}
tempNode->next = newNode;
(*L)->data++;
}
void PopBack(LinkList *L)
{
Node *tempNode = (*L);
if (tempNode->next == NULL)
{
return;
}
while (tempNode->next->next != NULL)
{
tempNode = tempNode->next;
}
free(tempNode->next);
tempNode->next = NULL;
(*L)->data--;
}
void viewlist(LinkList *L)
{
Node *p;
if ((*L)->next == NULL)
{
printf("
list is empty");
}
else
{
p = (*L)->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
}
}
int FindElemAtPos(LinkList *L, int pos)
{
int temppos = 0;
Node *p = (*L);
while (temppos != pos)
{
p = p->next;
temppos++;
}
return p->data;
}
void PopElement(LinkList *L, int pos)
{
Node *p = (*L);
int temppos = 0;
while (temppos != (pos - 1))
{
p = p->next;
temppos++;
}
Node *atpos = p->next;
p->next = atpos->next;
free(atpos);
(*L)->data--;
}20201008更
想到一个问题,网上搜到的资料说链表的插入时间复杂度是O(1),但是真的是O(1)吗,在第n个位置插入元素时首先要定位到n-1个结点,这是个查找的过程,复杂度是O(n),只是插入的过程是常数时间,但是如果要插入好多元素呢,这时候的差别就体现出来了,关于这个问题知乎有相似的问题:https://www.zhihu.com/question/51545092






鲁公网安备 37148202000241号