数据结构与算法(线性表)
线性表(线性存储结构)
就是把数据串起来,存放到物理地址中。将具有“一对一”关系的数据“线性”地存储到物理空间中,这种存储结构就称为线性存储结构(简称线性表)。
顺序存储结构
如图3a将数据存储在连续的物理地址上。顺序表存储数据时候,将所有的数据在连续的地址上存储,中间不留间隙。
顺序表的初始化
使用顺序表之前,需要申请空间,还要记录申请的存储容量和表中数据元素的个数。
- 定义一个线性表,向里面放入元素
#include <stdio.h>
#include <stdlib.h>
typedef struct Table{
int * head;
int length;
int size;
}table;
table initTable(){
table t;
t.head=(int*)malloc(5*sizeof(int));
if(!t.head){
printf("初始化失败");
exit(0);
}else{
printf("初始化成功!");
}
t.length=0;
t.size=5;
return t;
}
int main(int argc, char *argv[]) {
table t=initTable();
printf("表的大小为%d",t.length);
int i;
for(i=0;i<5;i++){
t.head[i]=i;
t.length++;
}
for(i=0;i<t.size;i++){
printf("\n");
printf("%d",t.head[i]);
}
return 0;
}
顺序表插入元素
- 插到表头
- 插到表尾
- 插到中间
插入元素进行两部操作:将要插入位置的元素以及后面的元素整体向后移动,将元素添加到空出来的位置上。
// 在指定位置插入元素
table addElement(table t,int element,int pos){
// 插在表尾部
if(pos==t.length){
// 重新申请大小
t.head=(int*)realloc(t.head,(t.size+1)*sizeof(int));
if(!t.head){
printf("扩容失败!");
return t;
}
t.size+=1;
}
if(pos>t.size+1 || pos<1){
printf("插入位置错误");
exit(0);
}
// 将插入位置以及之后的元素向后移动
int i;
for(i=t.length-1;i>=pos-1;i--){
t.head[i+1]=t.head[i];
}
// 将元素放到空的位置
t.head[pos-1]=element;
t.length++;
return t;
}
顺序表删除元素
直接将指定删除位置之后的元素向前移动一个,就可以删除指定为值的线性表。
table delTable(table t, int add) {
int i;
if (add > t.length || add < 1) {
printf("被删除元素的位置有误");
exit(0);
}
//删除操作
for (i = add; i < t.length; i++) {
t.head[i - 1] = t.head[i];
}
t.length--;
return t;
}
查找元素
-
找到目标元素;
-
直接修改该元素的值;
//更改函数,其中,elem为要更改的元素,newElem为新的数据元素
table amendTable(table t, int elem, int newElem) {
int add = selectTable(t, elem);
t.head[add - 1] = newElem;//由于返回的是元素在顺序表中的位置,所以-1就是该元素在数组中的下标
return t;
}
链式存储结构
如图3b将数数据分散的存储在物理地址上,但是数据的顺序还是没有变,通过一根线保持数据之间的逻辑顺序。
链式存储的特点
用一组任意的存储单元存储数据元素,这组存储单元可以是连续的也可以是不连续的。
链表
链表的概念
- 数据域:存储数据元素信息的域称为数据域。
- 指针域:存储直接后继位置的域称为指针域。
- n个节点链接成一个链表,即为线性表的链式存储结构
单链表
链表的每个结点中只包含一个指针域,指针域中存储的信息叫链,链的每个节点只有一个。链表中第一个结点的存储位置叫做头指针”,如果链表有头结点,那么头指针就是指向头结点数据域的指针。
节点的定义
// 定义链表
typedef struct Node{
// 数据域
Item item;
// 指向后继节点的指针
struct Node *next;
}Node,*List;
数据域数据的结构体
/*数据域的数据结构体*/
typedef struct Contet{
int id;
char name[20];
}Item;
初始化链表
// 初始化一个链表
List init(){
// 定义头节点
List head=(List)malloc(sizeof(Node));
if(!head){
printf("分配内存空间失败!");
return 0;
}else{
printf("内存分配成功链表创建!");
// 指针域为空
head->next=NULL;
return head;
}
}
链表中增加数据
// 增加数据
void insert(List head){
// 定义新的节点对象
Item item;
printf("输入编号:");
scanf("%d",&item.id);
printf("输入姓名:");
scanf("%s",&item.name);
// 清空缓冲区
getchar();
List p=(List)malloc(sizeof(Node));
p->item=item;
p->next=head->next;
head->next=p;
}
链表删除数据
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/*数据域的数据结构体*/
typedef struct Contet{
int id;
char name[20];
}Item;
// 定义链表
typedef struct Node{
// 数据域
Item item;
// 指向后继节点的指针
struct Node *next;
}Node,*List;
// 初始化一个链表
List init(){
// 定义头节点
List head=(List)malloc(sizeof(Node));
if(!head){
printf("分配内存空间失败!");
return 0;
}else{
printf("内存分配成功链表创建!");
printf("\n");
// 指针域为空
head->next=NULL;
return head;
}
}
// 增加数据
void insert(List head){
// 定义新的节点对象
Item item;
printf("输入编号:");
scanf("%d",&item.id);
printf("输入姓名:");
scanf("%s",&item.name);
// 清空缓冲区
getchar();
List p=(List)malloc(sizeof(Node));
p->item=item;
p->next=head->next;
head->next=p;
}
int main(int argc, char *argv[]) {
// 初始化链表
List head=init();
int n;
printf("输入你想录入数据的个数:");
scanf("%d",&n);
int i;
for(i=0;i<n;i++){
insert(head);
}
Item *p;
p=head->next;
printf("当前人编号:%d",p->id);
printf("当前人姓名:%s",p->name);
return 0;
}
数组
在java中当创建数组时会在内存中划分出一块连续的内存,然后当有数据进入的时候会将数据按顺序的存储在这块连续的内存中。当需要读取数组中的数据时,需要提供数组中的索引,然后数组根据索引将内存中的数据取出来,返回给读取程序。在Java中并不是所有的数据都能存储到数组中,只有相同类型的数据才可以一起存储到数组中。
特点
- 存储顺序是按照顺序存储,存储数据的内存也是连续的。
- 寻址读取数据比较容易,但是插入和删除比较困难。
应用
动态数组ArrayList
- ArratList相当于一个动态数组,支持扩容。
- 数组在定义的时候,因为需要给它分配连续的内存空间,需要预先指定其大小,当存放的数据大于其大小的时候,我们需要从新分配一块更大的空间,把原来的复制过去在插入新的元素。
- ArrayList中,当空间不够用的时候,它会自动扩容为原来的1.5倍的大小。
静态数组
- Java 中定义数组的语法有两种:
type arrayName[];
type[] arrayName;
队列
队列是一种先进先出的数据结构,数组和链表也都可以生成队列。当数据进入到队列中时也是先进入的在下面后进入的再上面,但是出队列的时候是先从下面出,然后才是上面的数据出,最晚进入的队列的,最后出。
@Test
public void test(){
Queue<Integer> queue=new LinkedList<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
queue.offer(6);
queue.forEach(System.out::println);
}
阻塞队列
并发队列
栈
栈是一种先进后出的数据结构,数组和链表都可以生成栈。当数据进入到栈时会按照规则压入到栈的底部,再次进入的数据会压在第一次的数据上面,以此类推。在取出栈中的数据的时候会先取出最上面的数据,所以是先进后出。
@Test
public void test1(){
Stack<Integer> stack=new Stack<>();
stack.push(1);
stack.push(2);
stack.push(4);
stack.forEach(System.out::println);
}
。。。。。。未完待续