zoukankan      html  css  js  c++  java
  • 线性表之链表实现:单向链表、循环链表、双向链表

    线性表

    单向链表实现:

    • 优点:便于插入和删除
    • 缺点:查找数据需要遍历

    声明

    • 一个数据+一个指针
    typedef struct LNode *List;
    struct LNode
    {
    	int Data;
    	List next;
    };
    

    求表长

    • 遍历表,当指向节点的指针为NULL时停止
    int Length(List PtrL)
    {
    	List p = PtrL;
    	int j = 0;
    	while (p)
    	{
    		p = p->next;
    		j++;
    	}
    	return j;
    }
    

    查找数据

    • 当指针不为NULL或者未找到数据时,继续循环

    按值查找

    List Find(int X, List PtrL)
    {
    	List p = PtrL;
    	while (p!=NULL && p->Data != X)p = p->next;
    	return p;
    }
    

    按序号查找

    List FindKth(int K, List PtrL)
    {
    	List p = PtrL;
    	int i = 1;
    	while (p != NULL&&i < K)
    	{
    		p = p->next;
    		i++;
    	}
    	if (i == K)return p;
    	else return NULL;
    }
    

    插入数据

    • 当插在第一个位置时:创建节点,让该节点直接指向头结点。
    • 当插在第i个位置时:创建节点,让该节点指向该位置的后一个节点,再让这个位置的节点指向插入的节点。
    List Insert(int X, int i, List PtrL)
    {
    	List p, s;
    	if (i == 1)
    	{
    		s = (List)malloc(sizeof(struct LNode));
    		s->Data = X;
    		s->next = PtrL;
    		return s;
    	}
    	p = FindKth(i-1, PtrL);
    	if (p == NULL)
    	{
    		printf("Error!");
    		return NULL;
    	}
    	else
    	{
    		s = (List)malloc(sizeof(struct LNode));
    		s->Data = X;
    		s->next = p->next;
    		p->Data = s;
    		return PtrL;
    	}
    }
    

    删除数据

    • 当删除头结点时,用一个临时指针指向头结点,将第二个结点当作头结点,再释放原头结点的内存。
    • 当删除中间结点时,用一个临时指针指向该中间结点,该位置结点指向下一个结点,再释放要删除的结点的内存。
    • p指针指向要删除结点的前一个结点,要注意指向的结点是否为NULL;
    List Delete(int i,List PtrL)
    {
    	List p, s;
    	if (i == 1)
    	{
    		s = PtrL;
    		if (PtrL != NULL)PtrL = PtrL->next;
    		else return NULL;
    		free(s);
    		return PtrL;
    	}
    	p = FindKth(i - 1, PtrL);
    	if (p == NULL)
    	{
    		printf("The %d node is not exited!",i-1);
    		return NULL;
    		}
    	else if (p->next == NULL)
    	{
    		printf("The %d node is not exited!", i);
    		return NULL;
    	}
    	else
    	{
    		s = p->next;
    		p->next = s->next;
    		free(s);
    		return PtrL;
    	}
    }
    

    输出数据

    void Print(List PtrL)
    {
    	while (PtrL != NULL)
    	{
    		printf("%d ", PtrL->Data);
    		PtrL = PtrL->next;
    	}
    	return;
    }
    

    注意

    • 自定义的线性表并不一定更要按标准,顾名思义,自定义线性表就是自定义,完全可以自己大胆改变线性表的内容。

    循环链表

    • 最后一个元素不指向空指针而是指向头节点,形成一个环,这样首尾相接的链表就称为循环链表。

    优点

    • 查找第一个元素和最后一个元素花费时间降为O(1)。

    改变

    • 最后一个元素指向头结点。与next原先指向空指针的操作均要改为头结点。

    双向循环链表

    • 在结点中同时储存两个指针,分别用于指向前驱和后继,同时最后一个指针指向头结点。

    优点

    • 便于查找前驱后继。
    • 查找第一个元素和最后一个元素花费时间降为O(1)。
    • 便于反向遍历。

    实现代码

    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    typedef struct node Node;
    typedef struct node *link;
    
    struct node
    {
    	int element;
    	link left;
    	link right;
    };
    
    typedef struct dlist *List;
    typedef struct dlist Dlist;
    
    typedef struct dlist
    {
    	int n;
    	link leftEnd, rightEnd;
    	link header;
    };
    link NewNode()
    {
    	link L;
    	L = (link)malloc(sizeof(Node));
    	return L;
    }
    List ListInit()
    {
    	node* y;
    	List L = (List)malloc(sizeof(dlist));
    	y = NewNode();
    	y->left = y;
    	y->right = y;
    	L->header = y;
    	L->n = 0;
    	return L;
    }
    int ListRetrieve(int k, List L)
    {
    	int i = 1;
    	link p;
    	p = L->header->right;
    	if (k<1 || k>L->n)printf("out of bounds");
    	while (i < k) { p = p->right; i++; }
    	return p->element;
    }
    int ListLocate(int x, List L)
    {
    	int i = 0;
    	link p;
    	p = L->header->right;
    	L->header->element = x;
    	while (p->element!=x) { p = p->right; i++; }
    	return ((p == L->header) ? 0 : i);
    }
    void ListInsert(int x, int k, List L)
    {
    	int i = 0;
    	link p, y;
    	p = L->header;
    	for (i = 1; i < k; i++) { p = p->right; }
    	y = NewNode();
    	y->element = x;
    	y->left = p;
    	y->right = p->right;
    	p->right->left = y;
    	p->right = y;
    	L->n++;
    	return;
    }
    int ListDelete(int k, List L)
    {
    	int x;
    	link p;
    	if (k<1 || k>L->n)printf("out of bounds");
    	p = L->header;
    	int i = 1;
    	for (i = 1; i < k; i++)p = p->right;
    	p->left->right = p->right;
    	p->right = p->left;
    	x = p->element;
    	free(p);
    	return x;
    }
    void PrintList(List L)
    {
    	link p;
    	for (p = L->header->right; p != L->header; p = p->right)
    		printf("%d ",p->element);
    	return;
    }
    
  • 相关阅读:
    MyBatis 笔记
    Python os模块、os.path模块常用方法
    vue-lazyload 的使用(vue图片懒加载)
    使用 vant 的 v-lazy 实现图片 vue 在移动端的懒加载
    代码注释规范-IDEA 配置 Java 类方法注释模板
    Java Web 笔记(杂)
    tortoisegit使用
    git结合github远程仓库使用
    .doc 2 .docx可用代码
    惊奇,MySQL还能正则匹配,简易例子
  • 原文地址:https://www.cnblogs.com/vancasola/p/7622821.html
Copyright © 2011-2022 走看看