单链表
单链表存储一个直接后继的地址,用一组任意的存储单元存储线性表中的元素。
数据域(数据元素)+指针域(指示后继元素存储位置) = 结点,如下图: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