线性表

线性表是一种逻辑结构,数据元素相同且有明确的前后次序。线性表可分为顺序存储和链式存储两种物理实现方式。顺序存储通过数组实现,查找效率高但插入删除操作可能涉及大量元素移动。链式存储则允许存储空间不连续,插入删除操作便捷但查找效率较低。

一、简介

数据结构分为物理结构和逻辑结构,逻辑结构分为线性结构、几何结构、树形结构和图形结构四大结构。其中,线性表就属于线性结构。

线性表:一种逻辑结构,相同数据类型的n个数据元素的有限序列,除第一个元素外,每个元素有且仅有一个直接前驱,除最后一个元素外,每个元素有且仅有一个直接后继。

线性表的特点:

  1. 元素个数有限
  2. 逻辑上元素有先后次序
  3. 数据类型相同
  4. 仅讨论元素间的逻辑关系

二、线性表的基本操作

InitList(*L): 初始化操作,建立一个空的线性表L。

ListEmpty(L): 判断线性表是否为空表,若线性表为空,返回true,否则返回false。

ClearList(*L): 将线性表清空。 

GetElem(L,i,*e): 将线性表L中的第i个位置元素值返回给e。

LocateElem(L,e): 在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回0表示失败。

ListInsert(*L,i,e): 在线性表L中第i个位置插入新元素e。

ListDelete(*L,i,*e): 删除线性表L中第i个位置元素,并用e返回其值。

ListLength(L): 返回线性表L的元素个数。

三、线性表分类

按物理结构分类:顺序存储和链式存储

1. 顺序存储

顺序表,使用数组实现,一组地址连续的存储单元,数组大小有两种方式指定,一是静态分配,二是动态扩展。

注:线性表从1开始,而数组从0开始。

优点:随机访问特性,查找O(1)时间,存储密度高;逻辑上相邻的元素,物理上也相邻;

缺点:插入删除需移动大量元素。

2. 链式存储

用一组任意的存储单元存储线性表的数据元素,这组存储单元可以存在内存中未被占用的任意位置。
也就是说,链式存储结构的线性表由一个(可以使零)或者多个结点(Node)组成。每个节点内部又分为数据域和指针域(链)。数据域存储了数据元素的信息。指针域存储了当前结点指向的直接后继的指针地址。
因为每个结点只包含一个指针域,所以叫做单链表。顾名思义,当然还有双链表。

与顺序存储相比,允许存储空间不连续,插入删除时不需要移动大量的元素,只需修改指针即可,但查找某个元素,只能从头遍历整个链表。


四、代码实现

  1. C语言

     #include <stdio.h>
     #include <stdlib.h>
     #include <stdbool.h>
     
     
     /*
     声明一个struct node的结构体类型,
     包含数据域data和指向struct node变量的指针域,
     利用typedef,将Node代替struct node,将PNode代替struct node*
     */
     typedef struct node
     {
     	int data;
     	struct node* next;
     }Node,*PNode;
     
     //对链表操作函数的声明
     PNode createList();
     int lengthList(PNode);
     void sortList(PNode);
     bool insertList(PNode,int,int);
     bool deleteList(PNode,int,int*);
     void traverseList(PNode);
     
     int main()
     {
     	int len = 0;//定义变量len,存放链表的长度
     	int val = 0;//存放链表被删除位置的值
     	PNode p_head = NULL;
     
     	p_head = createList();//p_head指向链表的头结点
     	len = lengthList(p_head);
     
     	printf("链表的长度: %d\n",len);
     	printf("原始链表:\n");
     	traverseList(p_head);//遍历链表,依次输出
     
     	sortList(p_head);//对链表进行排序
     
     	printf("排序后的链表:\n");
     	traverseList(p_head);
     }
     
     
     /*
     创建指定大小的链表,并对其数据域赋值,
     返回头结点的地址
     */
     PNode createList()
     {
     	int len,val;//len为链表长度,val存放数据域的值
     	printf("请输入元素个数:");
     	scanf("%d",&len);
     
     	PNode p_head = (PNode)malloc(sizeof(Node));//申请一个大小为Node的动态空间,p_head指向该内存
     	PNode p_tail = p_head;//p_tail指向链表的最后一个元素,将头结点的地址赋值给PTail
     	p_tail->next = NULL;//头节点的指针域置为空
     
     	PNode p_new = NULL;
     	for(int i=0;i<len;i++)
     	{
     		printf("请输入元素的值:");
     		scanf("%d",&val);
     		p_new = (PNode)malloc(sizeof(Node));//申请一个大小为Node的动态空间,PNew指向该内存
     		p_new->data = val;//将val赋值给PNew的数据域
     		p_tail->next = p_new;//将PNew赋值给PTail的指针域,添加到链表的最后
     		p_new->next=NULL; //将PNew的指针域设置为空
     		p_tail=p_new; //再次PTail指向链表的最后一个元素
     	}
     
     	return p_head;//返回头结点的地址
     }
     
     
     /*
     传入头结点的地址,利用while循环遍历输出链表
     */
     void traverseList(PNode p_head)
     {
     	PNode p = p_head->next;//将头结点的指针域赋值给p
     	while(p!=NULL)//判断p是否为空,如果为空则跳出循环
     	{
     		printf("%d\t",p->data); //输出p的数据域
     		p=p->next; //p指向下一个指针域
     	}
     
     	printf("\n");
     	return;
     }
     
     
     /*
     传入头结点的地址,利用while循环返回链表的长度
     */
     int lengthList(PNode p_head)
     {
     	PNode p = p_head->next;
     	int len = 0;
     	while(p!=NULL)
     	{
     		len++;
     		p = p->next;
     	}
     
     	return len;
     }
     
     
     /*
     传入头结点的地址,插入位置pos和插入的值val,
     先找到插入的pos位置的前一个元素的地址,然后将PNew的指针域赋值为pos-1的指针域,
     将pos-1的指针域指向PNew
     */
     bool insertList(PNode p_head,int pos,int val)
     {
     	int i=0;
     	PNode p = p_head;
     
     	while(i<pos-1 && p!=NULL)//利用while循环找pos的上一个元素
     	{	
     		p=p->next;
     		i++;
     	}
     
     	if(i>pos-1 || p==NULL)//插入的位置不合理,则返回false
     	{
     		printf("插入的位置不合理!\n");
     		return false;
     	}
     
     	PNode p_new = (PNode)malloc(sizeof(Node));
     	p_new->data = val;
     	p_new->next = p->next;
     	p->next = p_new;
     
     	return true;
     }
     
     /*
     传入头结点的地址,插入位置pos和变量val的地址,
     先找到pos-1位置的地址,然后将该元素的指针域指向的数据赋值给*val
     将pos-1的指针域被赋值为下一个元素的指针域
     */
     bool deleteList(PNode p_head,int pos,int* val)
     {
     	int i=0;
     	PNode p = p_head;
     
     	while(i<pos-1 && p!=NULL) //找到pos位置的元素
     	{
     		p=p->next;
     		i++;
     	}
     
     	if(i>pos-1||p==NULL)
     	{
     		printf("删除的位置不合理!\n");
     		return false;
     	}
     
     	PNode q = p->next;//指针q指向的元素将被删除
     	*val = q->data;//将q指向的数据赋值给*val
     	p->next = p->next->next;//将删除元素的上一个元素的指针域赋值为删除元素的下一个指针域
     	free(q); //释放q指向的内存
     	return true;
     }
     
     /*
     传入头结点的地址,利用选择排序算法对链表进行排序
     */
     void sortList(PNode p_head)
     {
     	PNode p,q;//定义结构指针p,q
     	int len = lengthList(p_head);//获得链表的长度len
     	int i,j,temp;
     	for(i=0,p=p_head->next;i<len-1;i++,p=p->next)
     	{
     		for(j=i+1,q=p->next;j<len;j++,q=q->next)
     		{
     			if(p->data>q->data)
     			{
     				temp=p->data; //利用temp,将p->data与q->data的值交换
     				p->data=q->data;
     				q->data=temp;
     			}
     		}
     	}
     }
    
  2. js语言

     function LinkedList(){
     	var head = null;
     	var len = 0;
     
     	var Node = function(_data){
     		this.data = _data;
     		this.next = null;
     	};
     
     	this.append = function(_data){
     		var node = new Node(_data);
     		var current;
     
     		if(head == null){//链表为空,添加到首部
     			head = node;
     		}else{
     			current = head;
     			//循环链表,直到找到最后一项
     			while(current.next){
     				current = current.next;
     			}
     
     			current.next = node;
     		}
     
     		len++;
     	};
     
     	this.removeAt = function(_pos){
     		if(_pos>-1 && pos<len){
     			var current = head;
     			var previous;
     			var index = 0;
     
     			if(_pos==0){
     				head = current.next;//移除第一个元素,直接把head指向下一个元素
     			}else{
     				while(index++ < _pos){
     					previous = current;
     					current = current.next;
     				}
     
     				//跳过current,将当前要移除的元素的上一个与下一项直接连接起来。
                 	previous.next = current.next;
     			}
     			
     			current = null;
     			
     			len--;
     
     			return true;
     		}else{
     			return false;
     		}
     	};
     
     	this.insert = function(_pos,_val){
     		if(_pos >= 0 && _pos <= len){
     			var node = new Node(_val)
     			var current = head;
     			var previous;
     			var index=0;
     
     			if(_pos === 0){//第一个位置
     				node.next = current;
     				head = node;
     			}else{
     				while (index++ < _pos ) { //循环迭代到目标位置
     	                previous = current; 
     	                current = current.next;
     	            }
     
     	            node.next = current; // node的下一个为current
     	            previous.next = node; // node的上一个位置为previous
     
     			}
     
     			len++;
     
     			return true;
     		}else{
     			return false;
     		}
     	};
     
     	this.toString = function(){
     		var current = head;
     		var string = '';
     
     		while(current){
     			string += current.data + (current.next ? '\n' : '');
     			current = current.next;
     		}
     
     		return string;
     	};
     
     	this.find = function(_val){
     		var current = head;
     		var index = 0;
     
     		while(current){
     			if(_val === current.data){
     				return index;
     			}
     
     			index++;
     			current = current.next;
     		}
     
     		return -1;
     	};
     
     	this.remove = function(_val){
     		var index = this.find(_val);
     		return this.removeAt(index);
     	};
     
     	this.length = function(){
     		return len
     	};
     }
     
     var list = new LinkedList()
     list.append(5)
     list.append(52)
     
     alert(list.toString())
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值