线性表查找分为顺序查找和折半查找
1)顺序查找:从表中最后一个记录开始,逐个进行记录的关键字和给定值比较,相等,则返回元素在表中的位置。
1 #include<stdio.h> 2 #include<stdlib.h> 3 typedef struct{ 4 int *elem; 5 int length; 6 }SSTable; 7 int Search_Seq(SSTable st,int key) 8 { 9 st.elem[0]=key; 10 for(int i=st.length;(st.elem[i]!=key)&&(i>0);--i) ; 11 return i; 12 if(i==0) 13 { 14 printf("抱歉,没有找到相应的元素!"); 15 } 16 } 17 int main() 18 { 19 int *b; 20 int n,k,s=0; 21 SSTable st; 22 printf("请输入元素的总个数: "); 23 scanf("%d",&n); 24 st.elem=(int *)malloc((n+1)*sizeof(int)); 25 st.length=n; 26 b=st.elem; 27 b++; 28 printf("输入各元素的值: "); 29 for(int i=0;i<n;i++,b++) 30 scanf("%d",b); 31 printf("请输入要查找的值: "); 32 scanf("%d",&k); 33 s=Search_Seq(st,k); 34 if(s!=0) 35 printf("%d",s); 36 }
有意思(以前写的代码,刚刚注意到scanf("%d",b)因为是多次输入需要在前面加空格,可是这次不加也可以了。)对scanf函数还没有很好的理解。。
我又犯傻了:(之前的代码有写注释的,我刚刚改了代码,但是不需要改的。。。)
补充:在查找之前先对st.elem[0]的关键字赋值key,目的在于免去查找过程中每一步都要检测整个表是否查找完毕。这也是这个算法的妙处
2)折半查找:以处于区间中间位置记录的关键字和给定值进行比较,若相等,则查找成功,不等则缩小范围,直至新的区间中间位置记录的值和给定的值相等。(针对有序表)
1 #include<stdio.h> 2 #include<stdlib.h> 3 typedef struct{ 4 int *elem; 5 int length; 6 }SSTable; 7 int Search_Seq(SSTable st,int key) 8 { 9 int low=1,high=st.length,mid; 10 while(low<=high) 11 { 12 mid=(low+high)/2; 13 if(st.elem[mid]==key) 14 return mid; 15 else if(key<st.elem[mid]) 16 high=mid-1; 17 else 18 low=mid+1; 19 } 20 return 0; 21 } 22 int main() 23 { 24 int *b; 25 int n,k,s=0; 26 SSTable st; 27 printf("请输入元素的总个数: "); 28 scanf("%d",&n); 29 st.elem=(int *)malloc((n+1)*sizeof(int)); 30 st.length=n; 31 b=st.elem; 32 b++; 33 printf("输入各元素的值: "); 34 for(int i=0;i<n;i++,b++) 35 scanf("%d",b); 36 printf("请输入要查找的值: "); 37 scanf("%d",&k); 38 s=Search_Seq(st,k); 39 if(s!=0) 40 printf("%d",s); 41 }
3)二叉排序树
概念:
1) 若根节点有左子树,则左子树的所有节点都比根节点要小
2) 若根节点有右子树,则右子树的所有节点都比根节点要大
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace BinarySortTree 7 { 8 public class Program 9 { 10 //定义一个二叉排序树结构 11 public class BSTree 12 { 13 public int data; 14 public BSTree left; 15 public BSTree right; 16 } 17 #region 创建二叉序树 18 static BSTree CreateBST(List<int> list) 19 { 20 BSTree bstree = new BSTree() 21 { 22 data=list[0], 23 left=null, 24 right=null 25 };//构造函数 26 for (int i = 1; i < list.Count; i++) 27 { 28 bool isExcute = false; 29 InsertBST(bstree,list[i],ref isExcute); 30 } 31 return bstree; 32 } 33 #endregion 34 #region 插入值到二叉树中 35 static void InsertBST(BSTree bstree, int key,ref bool isExcute) 36 { 37 if (bstree == null) 38 return; 39 if (bstree.data > key)//体会这里设计的妙处,如果大于的话就会递归调用这个函数,最后得到底层的,根书上的算法实现的功能类似,只不过,书上是用查找实现了,这一步可能还好些,因为避免出入相同的值 40 InsertBST(bstree.left, key, ref isExcute); 41 else 42 InsertBST(bstree.right,key,ref isExcute); 43 44 if (!isExcute) 45 { 46 BSTree current = new BSTree() 47 { 48 data=key, 49 left=null, 50 right=null 51 }; 52 //插入到父节点的当前元素 53 if (bstree.data > key) 54 bstree.left = current; 55 else 56 bstree.right = current; 57 isExcute = true; 58 } 59 } 60 #endregion 61 #region 查找节点 62 static bool SearchBST(BSTree bstree, int key) 63 { 64 if (bstree == null) 65 return false; 66 if (bstree.data == key) 67 return true; 68 if (bstree.data > key) 69 return SearchBST(bstree.left, key); 70 else 71 return SearchBST(bstree.right,key); 72 } 73 #endregion 74 static void LDR_BST(BSTree bstree) 75 { 76 if (bstree != null) 77 { 78 LDR_BST(bstree.left); 79 Console.Write(bstree.data + ""); 80 LDR_BST(bstree.right); 81 } 82 } 83 static void DeleteBST(ref BSTree bstree,int key) 84 { 85 if (bstree == null) 86 return; 87 if (bstree.data == key) 88 { 89 //为叶子节点 90 if (bstree.left == null && bstree.right == null) 91 { 92 bstree = null; 93 return; 94 } 95 //左子树不为空 96 if (bstree.left != null && bstree.right == null) 97 { 98 bstree = bstree.left; 99 return; 100 } 101 //右子树不为空 102 if (bstree.right != null && bstree.left == null) 103 { 104 bstree = bstree.right; 105 return; 106 } 107 //左右子树都不为空 108 if (bstree.left != null && bstree.right != null) 109 { 110 var node = bstree.right;//被删除节点的右孩子 111 BSTree lastNode = bstree; 112 while (node.left != null) 113 { 114 lastNode = node; 115 node = node.left; 116 } 117 bstree.data = node.data;//实现交换 118 if (lastNode.right == node) 119 {//删除节点的右节点没有左节点,有点拗口,不过理解了就好! 120 bstree.right = node.right; 121 } 122 else 123 { 124 if (lastNode.left == node) 125 { 126 lastNode.left = node.right; 127 } 128 } 129 node = null; 130 } 131 } 132 if (bstree.data > key) 133 { 134 DeleteBST(ref bstree.left, key); 135 } 136 else 137 { 138 DeleteBST(ref bstree.right,key); 139 } 140 } 141 static void Main(string[] args) 142 { 143 List<int> list = new List<int>() {50,30,70,10,40,90,80}; 144 BSTree bstree = CreateBST(list); 145 Console.Write("中序遍历的原始数据:"); 146 LDR_BST(bstree); 147 Console.Write("------------ "); 148 //查找一个节点 149 Console.WriteLine("在二叉树中是否包含:"+SearchBST(bstree,10)); 150 Console.Write("------------ "); 151 bool isExcute = false; 152 InsertBST(bstree,20,ref isExcute); 153 Console.WriteLine("插入到二叉树,中序遍历后:"); 154 LDR_BST(bstree); 155 Console.Write("------------ "); 156 Console.Write("删除叶子节点20,中序遍历后结果为:"); 157 DeleteBST(ref bstree,20); 158 LDR_BST(bstree); 159 Console.Write("删除叶子节点90,中序遍历后结果为:"); 160 DeleteBST(ref bstree, 90); 161 LDR_BST(bstree); 162 Console.ReadLine(); 163 } 164 } 165 }
4)哈希查找:
首先理解下哈希函数,比如5是一个要保存的数,丢给哈希函数后,返回一个2.那么此时5和2就建立了一种关系,这种关系就是哈希关系,在应用中,2是key,5是value
如何构造哈希函数:
1),直接定址法:
Key=value+c; c为一个常量,value+c就是一个简单的哈希函数
2),除法取余
Key=value%c;
3),数学分析法:
比如一组value1=112233,value2=112633,value3=119033,针对这样的数我们分析中间两个数比较波动,其他数不变,那么取key的值就可以是key1=22,key2=26,,key3=90
4),平方取中法:
取关键字平方后的中间几位为哈希地址。
5),折叠法
移位叠加:将分割后的每一部分的最低位对齐,然后相加;
间接叠加:从一端向另一端沿分割界来回折叠,然后对齐相加
如:0-442-20586-4
移位相加为 5864+4220+04=10088,去掉1为0088;
间接叠加为:5864+0224+04=6092
6),随机数法:
选择一个随机函数,取关键字的随机函数值作为它的哈希地址。
解决冲突的手法有:
1, 开放地址法:
Hi=(H(key)+di)MODm i=1,2,....k
1),di=1,2,3,4..m,称为线性探测再散列
2),di=1^2,-1^2,2^2,称为二次探测再散列
3),di为伪随机数序列,称为为随机探测再散列
2,再哈希法
Hi=RHi(key)
Rhi是不同的哈希函数
3, 链地址法
将所有关键字哈希的值相同的记录存储在同一线性链表中。
4, 建立一个公共溢出区
发生冲突后就填入溢出表。
用除法取余的方法构造哈希函数,用开放地址法中的线性探测再散列解决冲突。代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Hash 7 { 8 class Program 9 { 10 static int hashlength=13; 11 static int[] hash=new int[hashlength];//定义哈希表长度 12 //原数据 13 static List<int> list=new List<int>{10,20,64,32,55,42}; 14 15 static int SearchHash(int key,int hashlength,int[] hash) 16 { 17 int hashAddress = key % hashlength; 18 //指定hashAddress对应值存在但不是关键值,则用开放寻址法解决 19 while(hash[hashAddress]!=0&&hash[hashAddress]!=key) 20 { 21 hashAddress = (++hashAddress) % hashlength; 22 } 23 //查找到开放单元,也就是没有数据的单元 24 if (hash[hashAddress] == 0) 25 return -1; 26 return hashAddress; 27 } 28 static void InsertHash(int[] hash, int hashlength, int data) 29 { 30 int hashAddress = data % 13; 31 //不等于0时,说明产生了冲突,这时用开放寻址法中的线性探测再散列 32 while (hash[hashAddress] != 0) 33 { 34 hashAddress = (++hashAddress) % 13; 35 } 36 //实现插入功能 37 hash[hashAddress] = data; 38 } 39 static void Main(string[] args) 40 { 41 //创建hash 42 for (int i = 0; i < list.Count; i++) 43 { 44 InsertHash(hash, hashlength, list[i]); 45 } 46 Console.WriteLine("Hash数据:"+string.Join(",",hash)); 47 while (true) 48 { 49 Console.WriteLine(" 请输入要查找的数字:"); 50 int key = int.Parse(Console.ReadLine()); 51 var index = SearchHash(key,hashlength,hash); 52 if (index == -1) 53 Console.WriteLine("不好意思啦,主人,我没找到这个值:" + key); 54 else 55 Console.WriteLine("主人,找到你要找到值"+key+"位置是:"+index); 56 57 } 58 } 59 } 60 }
数据库的索引,说实话,在这之前,并不知道数据库的索引要怎样去建立。
数据库的索引其实是主键建立索引,方便我们在海量数据中查找。
索引查找时常用的三个术语
1, 主表,要查找的对象
2, 索引项,一般会用函数将一个主表划分成几个子表,每个子表建立一个索引,这个索引就是索引项
3, 索引项的集合是索引表
一般的索引项包含了三种内容:index,start,length
一:index,索引指向主表的关键字
二:start,index在主表中的位置
三:length,字表的区间长度
代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Index 7 { 8 class Program 9 { 10 class IndexItem 11 { 12 public int index; 13 public int start; 14 public int length; 15 } 16 //学生表 17 static int[] students ={ 18 101,102,103,104,105,0,0,0,0,0, 19 201,202,203,204,0,0,0,0,0,0, 20 301,302,303,0,0,0,0,0,0,0}; 21 //学生索引表 22 static IndexItem[] indexItem={ 23 new IndexItem(){index=1,start=0,length=5}, 24 new IndexItem(){index=2,start=10,length=4}, 25 new IndexItem(){index=3,start=20,length=3}}; //查找数据 26 public static int indexSearch(int key) 27 { 28 IndexItem item = null; 29 var index = key / 100; 30 //先找到索引 31 for (int i = 0; i < indexItem.Count();i++) 32 { 33 if (indexItem[i].index == index) 34 { 35 item = new IndexItem() { start=indexItem[i].start,length=indexItem[i].length}; 36 break; 37 } 38 } 39 //如果索引为空,则在索引表中查找失败 40 if (item == null) 41 return -1; 42 for (int i = item.start; i < item.start + item.length; i++) 43 { 44 if (students[i] == key) 45 { 46 return i; 47 } 48 } 49 //没找到时,返回-1 50 return -1; 51 } 52 //插入数据 53 public static int insert(int key) 54 { 55 IndexItem item = null; 56 var index = key / 100; 57 int i=0; 58 for (i = 0; i < indexItem.Count(); i++) 59 { 60 if (indexItem[i].index == index) 61 {//找到索引 62 item = new IndexItem() { 63 start=indexItem[i].start, 64 length=indexItem[i].length 65 }; 66 break; 67 } 68 } 69 if (item == null) 70 return -1; 71 students[item.start + item.length] = key; 72 indexItem[i].length++; 73 return 1; 74 } 75 static void Main(string[] args) 76 { 77 Console.WriteLine("原数据为:"+string.Join(",",students)); 78 int value = 205; 79 Console.WriteLine(" 插入数据"+value); 80 var index = insert(value); 81 if (index == 1) 82 { 83 Console.WriteLine(" 插入后数据:"+string.Join(",",students)); 84 Console.WriteLine(" 数据元素205在数组中的位置为" + indexSearch(205)); 85 } 86 Console.ReadLine(); 87 } 88 } 89 }