• 单链表的表示和实现 数据结构


    欢迎访问我的新博客:http://www.milkcu.com/blog/

    原文地址:

    基本概念

    链式存储结构,不要求逻辑上相邻的元素在物理上也相邻,没有顺序存储结构所具有的的弱点(在作插入或删除操作是,需移动大量元素),但同时也失去了顺序表可随机存取的优点。

    单链表的结点由数据域和指针域构成,多个结点链结成一个链表。

    代码实现

    # include <stdio.h>
    # include <stdlib.h>
    # define OK 1
    # define ERROR -1
    # define OVERFLOW -2
    
    typedef int ElemType;
    typedef int Status;
    
    typedef struct Lnode {
    	ElemType data;
    	struct Lnode * next;
    } Lnode, * LinkList;
    
    Status GetElem_L(LinkList L, int i, ElemType & e);
    Status ListInsert_L(LinkList & L, int i, ElemType e);
    Status ListDelete_L(LinkList & L, int i, ElemType & e);
    void CreateList_L(LinkList & L, int n);
    void MergeList_L(LinkList & La, LinkList & Lb, LinkList & Lc);
    Status ShowList_L(LinkList L);
    
    int main(void)
    {
    	//测试函数
    	LinkList L;
    	CreateList_L(L, 8);
    	ShowList_L(L);    //print create
    	ListInsert_L(L, 3, 3);
    	ShowList_L(L);    //print insert
    	ElemType e;
    	ListDelete_L(L, 4, e);
    	printf("delete e = %d\n", e);    //print e delete
    	ShowList_L(L);    //print delete
    	GetElem_L(L, 5, e);
    	printf("getelem e = %d\n", e);    //print getelem
    	LinkList Lb;
    	CreateList_L(Lb, 5);
    	ShowList_L(Lb);    //print Lb
    	LinkList Lc;
    	MergeList_L(L, Lb, Lc);
    	ShowList_L(Lc);    //print Lc
    	return 0;
    }
    
    Status GetElem_L(LinkList L, int i, ElemType & e)
    {
    	//算法2.8
    	//L为带头结点的单链表的头指针
    	Lnode * p = L->next;
    	int j = 1;
    	for(j = 1; p && j < i; j++) {
    		p = p->next;
    	}
    	if(!p) {
    		return ERROR;
    	}
    	e = p->data;
    	return OK;
    }
    
    Status ListInsert_L(LinkList & L, int i, ElemType e)
    {
    	//算法2.9
    	//在带头结点的单链线性表L中第i个位置之前插入元素e
    	Lnode * p = L->next;
    	int j = 1;
    	Lnode * s = (Lnode * ) malloc(sizeof(Lnode));
    	s->data = e;
    	for(j =1; p && j < i - 1; j++) {
    		p = p->next;
    	}
    	if(!p) {
    		return ERROR;
    	}
    	s->next = p->next;
    	p->next = s;
    	return OK;
    }
    
    Status ListDelete_L(LinkList & L, int i, ElemType & e)
    {
    	//算法2.10
    	Lnode * p = L->next;
    	int j = 1;
    	for(j = 1; p && j < i - 1; j++) {
    		p = p->next;
    	}
    	if(!p) {
    		return ERROR;
    	}
    	Lnode * q;
    	q = p->next;
    	e = q->data;
    	p->next = q->next;
    	free(q);
    	return OK;
    }
    
    void CreateList_L(LinkList & L, int n)
    {
    	//算法2.11
    	//逆位序输入n个元素的值,建立带表头结点的单链线性表L
    	L = (LinkList) malloc(sizeof(Lnode));
    	L->next = NULL;
    	for(int i = 0; i < n; i++) {
    		Lnode * p = (Lnode * ) malloc(sizeof(Lnode));
    		scanf("%d", & p->data);
    		p->next = L->next;
    		L->next = p;
    	}
    }
    
    void MergeList_L(LinkList & La, LinkList & Lb, LinkList & Lc)
    {
    	//算法2.12
    	//归并非递减排列的La和Lb到Lc
    	//用La的头结点作为Lc的头结点
    	//本算法具有副作用 
    	Lnode * pa = La->next;
    	Lnode * pb = Lb->next;
    	Lc = La;
    	Lnode * pc = Lc;
    	while(pa && pb) {
    		if(pa->data <= pb->data) {
    			pc->next = pa;
    			pc = pc->next;
    			pa = pa->next;
    		} else {
    			pc->next = pb;
    			pc = pc->next;
    			pb = pb->next;
    		}
    	}
    	pc = (pa ? pa : pb);
    	free(Lb);
    }
    
    Status ShowList_L(LinkList L)
    {
    	Lnode * p = L->next;
    	if(!p) {
    		return ERROR;
    	}
    	while(p) {
    		printf("%d  ", p->data);
    		p = p->next;
    	}
    	putchar('\n');
    	return OK;
    }

    算法分析

    GetElem_L()、ListInsert_L()、ListDelete_L()的时间复杂度均为O(n)。

    对于算法2.9的ListInsert_L()也可通过下面改进算法实现,该算法对于在单链表中指定结点前插入结点比较实用(时间复杂度为O(1)),代码如下:

    Status ListInsert_L(LinkList & L, int i, ElemType e)
    {
    	//算法2.9改进版
    	//在带头结点的单链线性表L中第i个位置之前插入元素e
    	Lnode * p = L->next;
    	int j = 1;
    	Lnode * s = (Lnode * ) malloc(sizeof(Lnode));
    	for(j = 1; p && j < i; j++) {
    		p = p->next;
    	}
    	if(!p) {
    		return ERROR;
    	}
    	//最终目的是在p前插入s 
    	s->next = p->next;
    	p->next = s;
    	s->data = p->data;
    	p->data = e;
    }

    对于算法2.10的ListDelete_L()也可通过下面函数实现,该算法对在于单链表中删除指定结点比较实用(时间复杂度为O(1)),代码如下:

    Status ListDelete_L(LinkList & L, int i, ElemType & e)
    {
    	//算法2.10改进版
    	//在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
    	//未引入临时变量
    	Lnode * p = L->next;
    	int j = 1;
    	for(j = 1; p && j < i; j++) {
    		p = p->next;
    	}
    	if(!p) {
    		return ERROR;
    	}
    	e = p->data;
    	p->data = p->next->data;
    	p->next = p->next->next;
    	free(& p->next);
    	return OK;
    }

    其实上面两个改进算法,在填空选择中经常用到。

    参考资料

    • 《数据结构:C语言版》(严蔚敏,吴伟民编著)

    (全文完)

  • 相关阅读:
    尴尬的事情又发生Newtonsoft.Json vs Protobuf.net
    python的多线程到底有没有用?
    Python中单线程、多线程和多进程的效率对比实验
    Python 一篇学会多线程
    Python中threading的join和setDaemon的区别及用法
    Python 函数定义以及参数传递
    python的thread和threading区别
    mod_python
    Maven 入门
    微信开发 没有认证过的服务号怎么办?微信提供了測试号(开通了认证过的服务号的功能)
  • 原文地址:https://www.cnblogs.com/milkcu/p/3808890.html
Copyright © 2020-2023  润新知