zoukankan      html  css  js  c++  java
  • [C++]数据结构:线性表之(单)链表

    一 (单)链表 ADT

    + Status InitList(LinkList &L) 初始化(单)链表

    + void printList(LinkList L) 遍历(单)链表

    + int ListLength(LinkList L) 获得表长

    + void CreateList_Head(LinkList &L, int n) 创建单链表 (头插法)【重点】

    + void CreateList_Rear(LinkList &L, int n) 创建单链表 (尾插法) 【重点】

    + Status GetElement(LinkList L, int i, ElementType &e) (按位)取值

    + LNode *LocateElement(LinkList L, ElementType e) (按值)查找

    + Status ListInsert(LinkList &L, int i, ElementType e) (按位)插入 【重点 | 易错】

    + Status ListDelete(LinkList &L, int i) (按位)删除  【重点 | 易错/易混】

    二 编程实现

    2.1 定义基础数据类型

    ElementType (数据元素类型/结构体)

    struct ElementType {
        char data; // char -> ElementType
     
        bool operator==(const ElementType b) const{ // 重载结构体 ElementType 的运算符
            return this->data == b.data;
        }
      
        bool operator!=(const ElementType b) const{
            return this->data != b.data;
        }
    };
    

    Status (状态/枚举类型)

    enum Status { ERROR, OK, OVERFLOW };
    

    LNode(单链表结点/结构体) / LinkList (单链表/结构体)

    typedef struct LNode { // typedef 关键字 可使用它来为类型取一个新的名称 like: typedef unsigned char BYTE; 
     	ElementType data; //数据域 
     	LNode *next; // 指针域
    }*LinkList; // *LinkList 本质上等同于 *LNode
    

    2.2 初始化(单)链表

    Status InitList(LinkList &L)

    Status InitList(LinkList &L){
    	L = new LNode; // 生成新结点 作为 头结点 , 头指针L指向头结点 
    	L->next = NULL; // next指针 置空(挂起)
    	return OK;
    }
    

    2.3 遍历(单)链表 

    void printList(LinkList L)

    void printList(LinkList L){
     	LNode *p;
     	p = L->next;
     	printf("[LinkList.h#printList] List->elements: ");
     	while(p != NULL){
     		printElementType(p->data);
     		printf("	");
     		p = p->next;
    	}
     	printf("
    ");
    }
    

    2.4 获得表长

    int ListLength(LinkList L)

    int ListLength(LinkList L){
    	LNode *p = L->next; // 指针p 指向首元结点 
    	int i = 0; //
    	while(p){ // 当前结点不为空 
    		p = p->next;
    		i ++; // 长度 +1
    	}
    	return i;
    }
    

    2.5-1 创建单链表 (头插法)

    void CreateList_Head(LinkList &L, int n)

    void CreateList_Head(LinkList &L, int n){ // n: 要输入的元素个数 
    	L = new LNode; // 生成头结点
    	L->next = NULL;
    	for(int i=0;i<n;i++){
    		LNode *s = new LNode; // 生成新结点 
    		printf("
    input -> element: ");
    		cin>>( s->data.data );
    		
    		s->next = L->next; //链接 新结点
    		L->next = s;
    	}
    }
    

    2.5-2 创建单链表 (尾插法) 

    void CreateList_Rear(LinkList &L, int n)

    void CreateList_Rear(LinkList &L, int n){ // n: 要输入的元素个数 
    	L = new LNode;
    	L->next = NULL;
    	
    	LNode *rear = L; // 初始化 尾指针 rear 指向 头结点
    	for(int j=0; j<n; j++){
    		LNode *s = new LNode; // 生成新结点 
    		printf("
    input -> element: ");
    		cin>>s->data.data;
    		
    		s->next = rear->next; //链接 新结点
    		rear->next = s;
    		
    		rear = rear->next; // 尾指针 rear 指向 新生成的尾结点
    	}
    }
    

    2.6 (按位)取值

    Status GetElement(LinkList L, int i, ElementType &e)

    Status GetElement(LinkList L, int i, ElementType &e){
    	LNode *p = L->next; // 指针p 指向首元结点
    	int j = 1;
    	while(p != NULL && j<i){
    		p = p->next;
    		j++;
    	}
    	if(j>i || p==NULL){ // i值不合法 i>n 或 i<0 
    		return ERROR;
    	}
    	e = p->data; // 赋值 
    	return OK;
    }
    

    2.7 (按值)查找 

    LNode *LocateElement(LinkList L, ElementType e)

    LNode *LocateElement(LinkList L, ElementType e){
    	LNode *p = L->next; // 指针p 指向首元结点
    	while(p!=NULL && p->data!=e){
    		p = p->next;
    	}
    	return NULL;
    }
    

    2.8 (按位)插入

    Status ListInsert(LinkList &L, int i, ElementType e)

    Status ListInsert(LinkList &L, int i, ElementType e){
    	LNode *p = L; // 指针p 指向头结点 【易错: 必须是头结点, 如果初始化p指向 首元结点(p = L->next), 那么 当i=1时, 会与 if(j>i-1 || p == NULL)中的"p == NULL"自相矛盾】 
    	int j = 0; // j 表示下标(明确j的意义很重要, 到底是 表示 下标(从0开始) 还是位置序号(从1开始) ) 
    	while(j<i-1 && p!= NULL){ // 移动指针p 指向 第 i-1 个元素上 (即 使得 下标 j 最大等于 i-2)
    		p = p->next;
    		j++;
    	}
    	if(j>i-1 || p == NULL){ // 判断 i 值 是否合法 i>n 或者 i<0 
    		return ERROR;
    	}
    	LNode *s = new LNode; // 生成新结点
    	s->data = e;
    	s->next = p->next; // 链接 新结点 与 原第 i 个结点 
    	p->next = s;	
    	return OK;
    }
    

    2.9 (按位)删除 

    Status ListDelete(LinkList &L, int i)

    Status ListDelete(LinkList &L, int i){
    	LNode *p = L; //指针p 指向首元结点 
    	int j = 0; // j 表示 下标 (j 用于 下一次的循环判断条件)
    	LNode *q; // 定位被删除结点 
    	while( (p != NULL) && (j<i-1) ){ // 指针p 移动到 第 i-1 个元素上 (即 j 最大取值为: i-1 )  
    	//【易混】  (p != NULL) 可以换成 (p->next != NULL),无任何影响,原因:设置该判断条件主要目的是 为了 指针p 能够继续往后移动 
    		printf("(old) p->data: %c
    ", p->data.data);
    		p = p->next;
    		printf("(new) p->data: %c
    --------------
    ", p->data.data);
    		j++;
    	}
    	if( j > i-1 || p->next == NULL ){ // 【易错: p != NULL (考虑的因素是: i>n )】 
    	//【易错】 此处的 p->next == NULL 的判断条件不能轻易换成 p == NULL 因为 必须满足 p 指向于 被删除的第 i 个 (非空)结点的前置结点 
    	// 即 要满足 第 i 个结点非空 ,且 p 指向的是其前置结点 所以 只能为 p->next == NULL 
    		printf("j:%d
    ", j);
    		return ERROR;
    	}
    	q = p->next;
    	p->next = q->next;
    	delete q; // 释放被删除结点的空间 
    	return OK;
    }
    

    三 测试运行(Main.cpp)

    #include <stdio.h>
    //#include <iostream.h>
    #include <iostream>
    using namespace std;
    
    #include "base.h"
    #include "LinkList.h"
    
    int main(){
    	LinkList L; // *LinkList 本质上等同于 *LNode
    	
    	InitList(L); // 初始化(单)链表 L 
    	
    	int i = ListLength(L);
    	printf("length: %d 
    ",i);
    	
    	ElementType e;
    	Status status;
    	
    	e.data = 'A';
    	status = ListInsert(L, 1, e);
    	printf("status (after insert) : %d
    ", status);
    	printList(L);
    	
    	e.data = 'B';
    	status = ListInsert(L, 2, e);
    	printf("status (after insert) : %d
    ", status);
    	printList(L);
    	
    	e.data = 'C';
    	status = ListInsert(L, 3, e);
    	printf("status (after insert) : %d
    ", status);
    	printList(L);
    	
    	status = ListDelete(L, 0);
    	printf("status (after delete) : %d
    ", status);
    	printList(L);
    	
    	status = ListDelete(L, 4);
    	printf("status (after delete) : %d
    ", status);
    	printList(L);
    	
    	status = ListDelete(L, 3);
    	printf("status (after delete) : %d
    ", status);
    	printList(L);
    			
    	CreateList_Rear(L, 5); // input:  A B C D E
    	printList(L);          
    	
    	return 0;
    }

    运行结果

    length: 0
    status (after insert) : 1
    [LinkList.h#printList] List->elements: A
    status (after insert) : 1
    [LinkList.h#printList] List->elements: A        B
    status (after insert) : 1
    [LinkList.h#printList] List->elements: A        B       C
    j:0
    status (after delete) : 0
    [LinkList.h#printList] List->elements: A        B       C
    (old) p->data: 
    (new) p->data: A
    --------------
    (old) p->data: A
    (new) p->data: B
    --------------
    (old) p->data: B
    (new) p->data: C
    --------------
    j:3
    status (after delete) : 0
    [LinkList.h#printList] List->elements: A        B       C
    (old) p->data: 
    (new) p->data: A
    --------------
    (old) p->data: A
    (new) p->data: B
    --------------
    status (after delete) : 1
    [LinkList.h#printList] List->elements: A        B
    
    input -> element: A
    
    input -> element: B
    
    input -> element: C
    
    input -> element: D
    
    input -> element: E
    [LinkList.h#printList] List->elements: A        B       C       D       E
    

    四 参考资料

    1 《数据结构(C语言版 第二版)》.严蔚敏.李冬梅.吴伟民

  • 相关阅读:
    java8大排序
    如何删除oracle 的用户及其数据
    JavaScript开发者常忽略或误用的七个基础知识点
    Vim学习指南
    5个开发人员不应该错过的最好跨平台PHP编辑器
    OpenGL 简介
    web 页面内容优化管理与性能技巧
    创建高性能移动 web 站点
    近期十大优秀jQuery插件推荐
    30本世界名著浓缩成的经典话语
  • 原文地址:https://www.cnblogs.com/johnnyzen/p/11405190.html
Copyright © 2011-2022 走看看